mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-08-14 13:15:14 +03:00
Font SubPixel antialiasing support for eterm and ui_html.
This commit is contained in:
337
.agent/plans/retained_text_small_batch_optimization_plan.md
Normal file
337
.agent/plans/retained_text_small_batch_optimization_plan.md
Normal file
@@ -0,0 +1,337 @@
|
||||
# Retained Text Small-Batch Optimization Plan
|
||||
|
||||
Status: proposal; no implementation started.
|
||||
|
||||
Date: 2026-07-25
|
||||
|
||||
## Goal
|
||||
|
||||
Determine whether small retained `Text` objects should submit their already-cached geometry to
|
||||
`GlobalBatchRenderer` instead of issuing independent direct draw calls, and implement that hybrid
|
||||
path only if controlled benchmarks show a meaningful improvement without regressing large text,
|
||||
ordinary grayscale rendering, LCD subpixel rendering, color emoji, or memory use.
|
||||
|
||||
The initial threshold to investigate is 512 rendered glyph quads, but 512 must not become a fixed
|
||||
policy until measurements establish the crossover point. The decision should use rendered geometry
|
||||
size rather than `String::size()` because shaping, whitespace, fallback glyphs, decorations, and
|
||||
outlines break the one-code-point/one-quad assumption.
|
||||
|
||||
In this document, “retained text” means a `Text` object with cached geometry that currently draws
|
||||
its arrays directly. It is not OpenGL instanced rendering (`glDraw*Instanced`). “Static text” means
|
||||
the static `Text::draw()` convenience path that emits glyphs into `GlobalBatchRenderer`.
|
||||
|
||||
## Current tradeoff
|
||||
|
||||
### Static `Text::draw()`
|
||||
|
||||
Advantages:
|
||||
|
||||
- Consecutive compatible strings can remain in one global batch.
|
||||
- Many small labels can become one draw submission instead of one submission per label.
|
||||
- The renderer already flushes when texture, blend state, or LCD coverage mode changes.
|
||||
|
||||
Costs:
|
||||
|
||||
- Glyph traversal and geometry emission happen on every call.
|
||||
- Shaped text may repeat layout work unless another layer caches it.
|
||||
- Vertices, texture coordinates, and colors are copied into the batch every frame.
|
||||
|
||||
### Retained `Text::draw()`
|
||||
|
||||
Advantages:
|
||||
|
||||
- Layout and vertex construction are cached until invalidated.
|
||||
- Large stable text avoids rebuilding and copying all of its geometry each frame.
|
||||
- Per-character colors and mixed render-mode ranges are already represented.
|
||||
|
||||
Costs:
|
||||
|
||||
- It flushes the global batch before drawing.
|
||||
- Every retained `Text` normally creates at least one independent draw submission.
|
||||
- LCD ranges require multiple channel passes; mixed mask/LCD content can create additional ranges.
|
||||
- A UI containing hundreds of short labels can become draw-call bound even though each label has
|
||||
very little geometry.
|
||||
|
||||
The proposed hybrid keeps retained layout/geometry caching but batches small cached geometry at draw
|
||||
time. Its cost is a bounded CPU-side copy into the batch in exchange for fewer flushes and draw
|
||||
calls.
|
||||
|
||||
## Questions the benchmark must answer
|
||||
|
||||
1. At what rendered-quad count does copying cached geometry into the global batch become slower than
|
||||
drawing the retained arrays directly?
|
||||
2. Does that crossover differ materially between OpenGL 2 (the primary renderer), GL3/core, and
|
||||
GLES2?
|
||||
3. How much does LCD rendering move the crossover because each LCD batch flush performs RGB and
|
||||
alpha passes?
|
||||
4. Do many small labels benefit more than a single string of the same total glyph count?
|
||||
5. How much time is actually spent in layout/geometry generation by static `Text::draw()` compared
|
||||
with submission and driver overhead?
|
||||
6. Does batching retained text reduce draw calls in realistic ecode UI scenes, or do intervening
|
||||
textures, clipping changes, and render modes force immediate flushes and erase the benefit?
|
||||
7. Is a fixed threshold sufficient, or should the decision also consider whether the cached text can
|
||||
join the batch currently being built?
|
||||
|
||||
## Candidate solutions
|
||||
|
||||
### Option A: Geometry-count threshold
|
||||
|
||||
For retained text below a configurable/internal threshold, append cached quads and colors to
|
||||
`GlobalBatchRenderer`. Draw larger text through the existing direct path.
|
||||
|
||||
Conceptually:
|
||||
|
||||
```cpp
|
||||
const size_t quadCount = mVertices.size() / GLi->quadVertex();
|
||||
if ( quadCount <= retainedTextBatchThreshold )
|
||||
submitCachedGeometryToBatch();
|
||||
else
|
||||
drawCachedGeometryDirectly();
|
||||
```
|
||||
|
||||
This is the simplest useful experiment. Candidate thresholds should include 0 (always direct), 32,
|
||||
64, 128, 256, 512, 1024, and an always-batched mode. The production value should be an internal
|
||||
constant unless runtime tuning proves necessary.
|
||||
|
||||
### Option B: Threshold plus batch compatibility
|
||||
|
||||
Batch only when the retained geometry can join a compatible pending batch. Compatibility includes:
|
||||
|
||||
- font atlas texture and coordinate type;
|
||||
- blend mode;
|
||||
- clipping/scissor state;
|
||||
- primitive representation;
|
||||
- LCD versus ordinary mask rendering;
|
||||
- active shader and any other renderer state that currently forces a flush.
|
||||
|
||||
If submitting a `Text` would create an otherwise empty batch that must be flushed immediately,
|
||||
direct drawing is likely cheaper. This option should follow Option A only if instrumentation shows
|
||||
that incompatible state transitions frequently defeat the size-only heuristic.
|
||||
|
||||
### Option C: Store render-mode runs instead of one mode per quad
|
||||
|
||||
Retained LCD text currently needs enough metadata to map every quad to its render mode. A compact
|
||||
run list can represent the common cases more efficiently:
|
||||
|
||||
```text
|
||||
first quad | quad count | mode
|
||||
0 | 34 | Subpixel
|
||||
34 | 1 | Color/Mask
|
||||
35 | 37 | Subpixel
|
||||
```
|
||||
|
||||
Uniform LCD text needs one run; all-mask text can keep the existing empty-vector fast path. The run
|
||||
list maps directly to drawing and batch submission. It avoids retaining a mode value per glyph but
|
||||
adds construction and invalidation complexity. Implement it only if memory measurements show the
|
||||
current sparse mode vector is material or if a run API substantially simplifies hybrid submission.
|
||||
|
||||
### Option D: Batch command references without copying geometry
|
||||
|
||||
Teach the renderer to queue references to immutable retained buffers and merge or multi-draw
|
||||
compatible commands later. This could avoid CPU copies, but it introduces lifetime, invalidation,
|
||||
ordering, clipping, and backend complexity. It is not the first implementation candidate. Consider
|
||||
it only if Option A demonstrates that draw-call reduction is valuable but vertex copying prevents a
|
||||
useful crossover.
|
||||
|
||||
## Recommended implementation sequence
|
||||
|
||||
### Phase 1: Instrument the existing paths
|
||||
|
||||
Add benchmark-only or opt-in counters for:
|
||||
|
||||
- `Text` draw calls split by static and retained paths;
|
||||
- rendered quads and vertices;
|
||||
- global batch flush count and reason;
|
||||
- underlying `drawArrays()` calls;
|
||||
- LCD channel-pass draw calls;
|
||||
- texture, shader, clipping, blend, and render-mode transitions;
|
||||
- bytes copied into batch arrays;
|
||||
- retained geometry rebuild count and time.
|
||||
|
||||
Counters must be disabled or compile away in normal production builds unless their measured overhead
|
||||
is negligible. Do not add atomics or logging to the render loop.
|
||||
|
||||
### Phase 2: Build a dedicated text-rendering benchmark
|
||||
|
||||
Add a focused benchmark to `src/benchmarks/` and the existing `eepp-benchmarks` target. It should
|
||||
create one window/context, preload every glyph and atlas page, warm up shader creation, and run all
|
||||
strategies against identical geometry.
|
||||
|
||||
The benchmark must expose three forced policies so results are comparable:
|
||||
|
||||
- `direct`: existing retained draw path;
|
||||
- `batch`: force cached retained geometry through the proposed batch submission path;
|
||||
- `auto-N`: hybrid path with threshold `N`.
|
||||
|
||||
The forcing mechanism should be benchmark-only or a narrow internal testing hook, not a permanent
|
||||
public `Text` API.
|
||||
|
||||
### Phase 3: Implement cached-geometry batch submission
|
||||
|
||||
Add a bulk submission API to `BatchRenderer` rather than calling its per-quad API in a loop if the
|
||||
bulk API can preserve existing array growth and state invariants. It should accept non-owning spans
|
||||
for the duration of the call and copy once into already-reserved batch storage. It must not allocate
|
||||
per glyph.
|
||||
|
||||
Submit retained render-mode runs in original order:
|
||||
|
||||
- mask/decorations through the normal batch mode;
|
||||
- LCD glyph ranges through `setSubpixelText( true )`;
|
||||
- color glyphs through their established normal/color behavior;
|
||||
- outline, shadow, and fill in their existing paint order.
|
||||
|
||||
The path must preserve transforms, per-vertex colors, atlas coordinates, blend mode, clipping, and
|
||||
the current pixel alignment rules. Avoid converting cached geometry into temporary vectors.
|
||||
|
||||
### Phase 4: Tune and select the policy
|
||||
|
||||
Run the complete benchmark matrix on at least the primary OpenGL 2 renderer. Test another
|
||||
programmable backend where available. Select a threshold only when it improves the small-label
|
||||
workloads and does not materially regress large-text workloads.
|
||||
|
||||
Start with a simple fixed threshold. Add compatibility-aware logic only if counters demonstrate a
|
||||
real problem. Prefer the smallest policy that captures most of the measured benefit.
|
||||
|
||||
### Phase 5: Validate in ecode
|
||||
|
||||
Run ecode with its benchmark mode and representative layouts:
|
||||
|
||||
- empty editor with menus, tabs, status bar, and side panels;
|
||||
- a code document with typical visible line lengths;
|
||||
- multiple splits and minimap enabled;
|
||||
- terminal output with frequent updates;
|
||||
- menus and nested context menus containing many short labels;
|
||||
- grayscale and subpixel antialiasing;
|
||||
- color emoji embedded in UI/editor/terminal text.
|
||||
|
||||
Compare frame time and counters against the direct-retained baseline, not only maximum FPS.
|
||||
|
||||
## Benchmark matrix
|
||||
|
||||
### Geometry sizes
|
||||
|
||||
Use rendered glyph-quad counts near likely crossover points:
|
||||
|
||||
- 4, 8, 16, 32, 64, 128, 256, 512, 1024, and 4096 quads.
|
||||
|
||||
Include both one object of size `N` and many objects with the same aggregate glyph count. Examples:
|
||||
|
||||
- 1 × 512 glyphs;
|
||||
- 8 × 64 glyphs;
|
||||
- 32 × 16 glyphs;
|
||||
- 128 × 4 glyphs.
|
||||
|
||||
This distinguishes vertex-volume cost from per-object draw-call cost.
|
||||
|
||||
### Rendering content
|
||||
|
||||
Test each relevant coverage/state pattern:
|
||||
|
||||
- grayscale/mask-only text;
|
||||
- LCD subpixel-only text;
|
||||
- LCD text with occasional color emoji or grayscale fallback glyphs;
|
||||
- alternating render modes as an intentional worst case;
|
||||
- outline and shadow;
|
||||
- underline and strike-through;
|
||||
- per-character colors;
|
||||
- one shared atlas page versus strings spanning multiple atlas pages/fonts.
|
||||
|
||||
### Update patterns
|
||||
|
||||
- Stable retained geometry: draw the same objects for every measured frame.
|
||||
- Position-only movement: cached geometry remains valid but transforms change.
|
||||
- Color-only updates.
|
||||
- One object mutated per frame.
|
||||
- Every object mutated per frame.
|
||||
- Static `Text::draw()` baseline to quantify the full geometry-generation cost.
|
||||
|
||||
### Scene/state patterns
|
||||
|
||||
- All compatible text drawn consecutively.
|
||||
- Text interleaved with rectangles/icons using the same clipping region.
|
||||
- Text interleaved across different font textures.
|
||||
- Frequent clipping/scissor changes, representative of widgets and editor lines.
|
||||
- Empty batch before every label as a worst case for hybrid submission.
|
||||
- Existing compatible pending batch before every label as the best case.
|
||||
|
||||
## Measurement methodology
|
||||
|
||||
- Build and measure an optimized release configuration. Debug/ASan builds remain mandatory for
|
||||
correctness but are not performance evidence.
|
||||
- Disable VSync and frame-rate limits.
|
||||
- Preload fonts, glyphs, atlas pages, and the lazy LCD shader before timing.
|
||||
- Run warm-up frames until allocations and shader/driver initialization stabilize.
|
||||
- Use a fixed number of frames or submissions large enough to exceed timer noise.
|
||||
- Repeat each case several times and report median plus a tail measure such as p95; retain raw
|
||||
samples where practical.
|
||||
- Randomize or alternate policy order to reduce thermal and clock-frequency bias.
|
||||
- Keep window size, pixel density, font, font size, atlas contents, and visible output identical.
|
||||
- Prevent dead-code elimination and ensure submitted work is consumed.
|
||||
- Separate CPU submission time from completed GPU time. Use an explicit synchronization boundary
|
||||
outside the timed inner loop when comparing total frame completion, or GPU timer queries where
|
||||
supported. Do not put `glFinish()` after every individual text draw.
|
||||
- Record hardware, driver, renderer backend, build flags, and commit identifier with results.
|
||||
- Report milliseconds/frame and draw calls in addition to FPS. Very high FPS compresses meaningful
|
||||
differences and can obscure CPU/GPU synchronization effects.
|
||||
|
||||
## Metrics and decision criteria
|
||||
|
||||
Primary metrics:
|
||||
|
||||
- median and p95 CPU frame/submission time;
|
||||
- median completed frame time or GPU time;
|
||||
- GL draw calls per frame;
|
||||
- global batch flushes per frame;
|
||||
- bytes copied into batch storage per frame;
|
||||
- retained geometry rebuilds and allocations.
|
||||
|
||||
Suggested acceptance criteria:
|
||||
|
||||
- At least a repeatable 10% CPU-frame improvement in the many-small-label workload, or a substantial
|
||||
draw-call reduction that produces a measurable ecode improvement.
|
||||
- No more than a 2% regression in representative large stable editor/terminal workloads.
|
||||
- No measurable regression in the ordinary grayscale path when the hybrid path is disabled or the
|
||||
object exceeds the threshold.
|
||||
- No additional per-frame heap allocations after warm-up.
|
||||
- Exact visual equivalence in the existing subpixel golden test and new hybrid-specific golden
|
||||
cases.
|
||||
|
||||
If no threshold meets those criteria, keep the existing direct retained path and remove the
|
||||
experiment rather than retaining unused complexity.
|
||||
|
||||
## Correctness tests
|
||||
|
||||
Extend rendering tests before enabling the automatic policy:
|
||||
|
||||
- Render identical content through forced direct and forced batched-retained paths and compare the
|
||||
resulting images exactly where the backend is deterministic.
|
||||
- Cover text immediately below, at, and above the selected threshold.
|
||||
- Cover direct/static and retained text on both light and dark backgrounds.
|
||||
- Cover first-glyph LCD text to preserve the render-mode bookkeeping regression test.
|
||||
- Cover mixed LCD plus color emoji/fallback glyphs.
|
||||
- Cover mask-only text and verify it never enters the LCD compositor.
|
||||
- Cover outlines, shadows, underline, strike-through, per-character colors, fractional positions,
|
||||
clipping, transforms, and transparent framebuffers.
|
||||
- Verify invalidation after antialiasing changes rebuilds both geometry and texture coordinates.
|
||||
|
||||
The existing `FontRendering.subpixelCoverageCompositesPerChannel` golden is the baseline guard and
|
||||
must remain byte/pixel identical throughout threshold experiments.
|
||||
|
||||
## Performance and allocation constraints
|
||||
|
||||
- The normal mask-only path must not allocate render-mode metadata merely to support LCD text.
|
||||
- Bulk batch submission must reserve geometrically and avoid temporary per-draw vectors.
|
||||
- Do not add `std::function`, callbacks, dynamic dispatch, logging, or per-glyph heap activity to the
|
||||
render loop.
|
||||
- A run-based mode representation should use compact trivially copyable records and merge adjacent
|
||||
equal modes during geometry construction.
|
||||
- Threshold checks must be constant-time and based on already available geometry counts.
|
||||
- Any compatibility inspection must use cached renderer/batch state, not expensive GL state queries.
|
||||
|
||||
## Expected outcome
|
||||
|
||||
The likely useful design is a hybrid: small, compatible retained text copies cached geometry into
|
||||
the global batch, while large retained text continues to draw directly. The exact threshold may be
|
||||
well below 512 quads and may differ for LCD and mask text. Measurements, not the initial estimate,
|
||||
will decide whether one threshold, separate mode-specific thresholds, or no hybrid path is the best
|
||||
production choice.
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef EE_UI_UIAPPLICATION
|
||||
#define EE_UI_UIAPPLICATION
|
||||
|
||||
#include <eepp/graphics/font.hpp>
|
||||
#include <eepp/window/window.hpp>
|
||||
|
||||
#include <optional>
|
||||
@@ -45,6 +46,10 @@ class EE_API UIApplication {
|
||||
//! The default fallback font for the UI. If not provided it will load Droid Sans Fallback
|
||||
//! Full ( it will look at "assets/fonts/DroidSansFallbackFull.ttf" )
|
||||
Font* fallbackFont{ nullptr };
|
||||
//! The hinting policy applied to fonts owned by the default and UI resource scopes.
|
||||
FontHinting fontHinting{ FontHinting::Full };
|
||||
//! The antialiasing policy applied to fonts owned by the default and UI resource scopes.
|
||||
FontAntialiasing fontAntialiasing{ FontAntialiasing::Grayscale };
|
||||
};
|
||||
|
||||
UIApplication( const WindowSettings& windowSettings, const Settings& appSettings = Settings(),
|
||||
@@ -70,6 +75,7 @@ class EE_API UIApplication {
|
||||
bool showMemoryManagerResult() const;
|
||||
|
||||
String::HashType getStyleSheetDefaultMarker() const { return mStyleSheetMarker; }
|
||||
|
||||
protected:
|
||||
UISceneNode* mUISceneNode{ nullptr };
|
||||
EE::Window::Window* mWindow{ nullptr };
|
||||
|
||||
@@ -161,9 +161,9 @@ class EE_API UISceneNode : public SceneNode {
|
||||
* @brief Binds an embedded scene to host-scene services without copying document state.
|
||||
*
|
||||
* Copies only shared platform/configuration services: dispatcher, DPI/window pointer,
|
||||
* thread pool, color/contrast preferences, and default font/theme pointers. Stylesheets,
|
||||
* URI, referer, cookies, navigation callbacks, actions, roots, resource scope, and dirty queues
|
||||
* remain owned by this scene.
|
||||
* thread pool, color/contrast and font-rendering preferences, and default font/theme pointers.
|
||||
* Stylesheets, URI, referer, cookies, navigation callbacks, actions, roots, resource scope, and
|
||||
* dirty queues remain owned by this scene.
|
||||
*/
|
||||
void initializeEmbeddedFromHost( UISceneNode* hostScene );
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <eepp/graphics/fontfamily.hpp>
|
||||
#include <eepp/graphics/fontservice.hpp>
|
||||
#include <eepp/graphics/fonttruetype.hpp>
|
||||
#include <eepp/scene/scenemanager.hpp>
|
||||
#include <eepp/system/filesystem.hpp>
|
||||
@@ -54,7 +55,14 @@ UIApplication::UIApplication( const WindowSettings& windowSettings, const Settin
|
||||
FileSystem::changeWorkingDirectory( path );
|
||||
}
|
||||
|
||||
FontService& defaultFontService = defaultResourceScope().getFontService();
|
||||
defaultFontService.setHinting( appSettings.fontHinting );
|
||||
defaultFontService.setAntialiasing( appSettings.fontAntialiasing );
|
||||
|
||||
mUISceneNode = UISceneNode::New();
|
||||
FontService& uiFontService = mUISceneNode->getResourceScope()->getFontService();
|
||||
uiFontService.setHinting( appSettings.fontHinting );
|
||||
uiFontService.setAntialiasing( appSettings.fontAntialiasing );
|
||||
SceneManager::instance()->add( mUISceneNode );
|
||||
|
||||
if ( !appSettings.loadBaseResources )
|
||||
|
||||
@@ -317,6 +317,10 @@ void UISceneNode::initializeEmbeddedFromHost( UISceneNode* hostScene ) {
|
||||
mThreadPool = hostScene->getThreadPool();
|
||||
mColorSchemePreference = hostScene->getColorSchemePreference();
|
||||
mContrastPreference = hostScene->getContrastPreference();
|
||||
const FontService& hostFontService = hostScene->getResourceScope()->getFontService();
|
||||
FontService& fontService = mResourceScope->getFontService();
|
||||
fontService.setHinting( hostFontService.getHinting() );
|
||||
fontService.setAntialiasing( hostFontService.getAntialiasing() );
|
||||
|
||||
UIThemeManager* hostThemeManager = hostScene->getUIThemeManager();
|
||||
if ( hostThemeManager ) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <args/args.hxx>
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
|
||||
EE_MAIN_FUNC int main( int argc, char** argv ) {
|
||||
std::shared_ptr<ThreadPool> threadPool(
|
||||
@@ -25,6 +26,23 @@ EE_MAIN_FUNC int main( int argc, char** argv ) {
|
||||
args::ValueFlag<Float> pixelDensityConf( parser, "pixel-density",
|
||||
"Set default application pixel density",
|
||||
{ 'd', "pixel-density" } );
|
||||
const std::unordered_map<std::string, FontHinting> fontHintingMap{
|
||||
{ "none", FontHinting::None },
|
||||
{ "slight", FontHinting::Slight },
|
||||
{ "full", FontHinting::Full },
|
||||
};
|
||||
args::MapFlag<std::string, FontHinting> fontHinting(
|
||||
parser, "font-hinting", "Font hinting mode (accepted values: none, slight, full)",
|
||||
{ "font-hinting" }, fontHintingMap, FontHinting::Full );
|
||||
const std::unordered_map<std::string, FontAntialiasing> fontAntialiasingMap{
|
||||
{ "none", FontAntialiasing::None },
|
||||
{ "grayscale", FontAntialiasing::Grayscale },
|
||||
{ "subpixel", FontAntialiasing::Subpixel },
|
||||
};
|
||||
args::MapFlag<std::string, FontAntialiasing> fontAntialiasing(
|
||||
parser, "font-antialiasing",
|
||||
"Font antialiasing mode (accepted values: none, grayscale, subpixel)",
|
||||
{ "font-antialiasing" }, fontAntialiasingMap, FontAntialiasing::Grayscale );
|
||||
|
||||
try {
|
||||
parser.ParseCLI( Sys::parseArguments( argc, argv ) );
|
||||
@@ -41,10 +59,14 @@ EE_MAIN_FUNC int main( int argc, char** argv ) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
UIApplication::Settings appSettings( {}, pixelDensityConf ? pixelDensityConf.Get() : 0.f );
|
||||
appSettings.fontHinting = fontHinting.Get();
|
||||
appSettings.fontAntialiasing = fontAntialiasing.Get();
|
||||
|
||||
UIApplication app(
|
||||
WindowSettings{ 1280, 720, "eepp - UI HTML Example", WindowStyle::Default,
|
||||
WindowBackend::Default, 32, Sys::getProcessPath() + "assets/icon/ee.png" },
|
||||
UIApplication::Settings( {}, pixelDensityConf ? pixelDensityConf.Get() : 0.f ),
|
||||
appSettings,
|
||||
ContextSettings( false,
|
||||
benchmarkMode.Get() ? 0 : ContextSettings::FrameRateLimitScreenRefreshRate,
|
||||
4 ) );
|
||||
|
||||
@@ -58,6 +58,30 @@ static bool readHttpRequestHeaders( TcpSocket& client, std::string* headers = nu
|
||||
return true;
|
||||
}
|
||||
|
||||
UTEST( UIWebView, DocumentSceneInheritsHostFontRenderingPolicy ) {
|
||||
auto win = Engine::instance()->createWindow(
|
||||
WindowSettings( 320, 240, "UIWebView Font Policy Test", WindowStyle::Default,
|
||||
WindowBackend::Default, 32, {}, 1, false, true ),
|
||||
ContextSettings( false, 0, 0, GLv_default, true, false ) );
|
||||
ASSERT_TRUE( win != nullptr );
|
||||
|
||||
UISceneNode* sceneNode = UISceneNode::New();
|
||||
FontService& hostFontService = sceneNode->getResourceScope()->getFontService();
|
||||
hostFontService.setHinting( FontHinting::Slight );
|
||||
hostFontService.setAntialiasing( FontAntialiasing::Subpixel );
|
||||
SceneManager::instance()->add( sceneNode );
|
||||
|
||||
UIWebView* webView = UIWebView::New();
|
||||
webView->setParent( sceneNode->getRoot() );
|
||||
UISceneNode* documentScene = webView->getDocumentSceneNode();
|
||||
ASSERT_TRUE( documentScene != nullptr );
|
||||
const FontService& documentFontService = documentScene->getResourceScope()->getFontService();
|
||||
EXPECT_EQ( FontHinting::Slight, documentFontService.getHinting() );
|
||||
EXPECT_EQ( FontAntialiasing::Subpixel, documentFontService.getAntialiasing() );
|
||||
|
||||
Engine::destroySingleton();
|
||||
}
|
||||
|
||||
UTEST( UIWebView, OwnedDocumentSceneScrollTarget ) {
|
||||
auto win = Engine::instance()->createWindow(
|
||||
WindowSettings( 640, 480, "UIWebView Document Scene Test", WindowStyle::Default,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <eepp/ee.hpp>
|
||||
#include <eterm/terminal/terminaldisplay.hpp>
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
|
||||
EE::Window::Window* win = NULL;
|
||||
std::shared_ptr<TerminalDisplay> terminal = nullptr;
|
||||
@@ -176,6 +177,23 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) {
|
||||
args::ValueFlag<std::string> fallbackFontPathF( parser, "fallback-fontpath",
|
||||
"Fallback Font path", { "fallback-font" } );
|
||||
args::ValueFlag<Float> fontSize( parser, "fontsize", "Font size (in dp)", { "fontsize" }, 11 );
|
||||
const std::unordered_map<std::string, FontHinting> fontHintingMap{
|
||||
{ "none", FontHinting::None },
|
||||
{ "slight", FontHinting::Slight },
|
||||
{ "full", FontHinting::Full },
|
||||
};
|
||||
args::MapFlag<std::string, FontHinting> fontHinting(
|
||||
parser, "font-hinting", "Font hinting mode (accepted values: none, slight, full)",
|
||||
{ "font-hinting" }, fontHintingMap, FontHinting::Full );
|
||||
const std::unordered_map<std::string, FontAntialiasing> fontAntialiasingMap{
|
||||
{ "none", FontAntialiasing::None },
|
||||
{ "grayscale", FontAntialiasing::Grayscale },
|
||||
{ "subpixel", FontAntialiasing::Subpixel },
|
||||
};
|
||||
args::MapFlag<std::string, FontAntialiasing> fontAntialiasing(
|
||||
parser, "font-antialiasing",
|
||||
"Font antialiasing mode (accepted values: none, grayscale, subpixel)",
|
||||
{ "font-antialiasing" }, fontAntialiasingMap, FontAntialiasing::Grayscale );
|
||||
args::ValueFlag<Float> width( parser, "winwidth", "Window width (in dp)", { "width" }, 1280 );
|
||||
args::ValueFlag<Float> height( parser, "winheight", "Window height (in dp)", { "height" },
|
||||
720 );
|
||||
@@ -258,6 +276,8 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) {
|
||||
displayManager->enableScreenSaver();
|
||||
displayManager->enableMouseFocusClickThrough();
|
||||
displayManager->disableBypassCompositor();
|
||||
defaultResourceScope().getFontService().setHinting( fontHinting.Get() );
|
||||
defaultResourceScope().getFontService().setAntialiasing( fontAntialiasing.Get() );
|
||||
|
||||
Sizei winSize( width.Get(), height.Get() );
|
||||
win = Engine::instance()->createWindow(
|
||||
@@ -326,6 +346,8 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) {
|
||||
MemoryManager::showResults();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
terminal->setFontHinting( fontHinting.Get() );
|
||||
terminal->setFontAntialiasing( fontAntialiasing.Get() );
|
||||
|
||||
terminal->getTerminal()->setAllowMemoryTrimnming( true );
|
||||
terminal->setCursorMode( cursorStyle.Get() );
|
||||
|
||||
Reference in New Issue
Block a user