@kurot/core 1.0.14 → 1.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -1
- package/dist/kurot/display/Bitmap.d.ts +0 -1
- package/dist/kurot/display/Bitmap.d.ts.map +1 -1
- package/dist/kurot/display/Bitmap.js +0 -3
- package/dist/kurot/display/Bitmap.js.map +1 -1
- package/dist/kurot/display/DisplayObject.d.ts +16 -35
- package/dist/kurot/display/DisplayObject.d.ts.map +1 -1
- package/dist/kurot/display/DisplayObject.js +6 -41
- package/dist/kurot/display/DisplayObject.js.map +1 -1
- package/dist/kurot/display/DisplayObjectContainer.d.ts +0 -10
- package/dist/kurot/display/DisplayObjectContainer.d.ts.map +1 -1
- package/dist/kurot/display/DisplayObjectContainer.js +0 -14
- package/dist/kurot/display/DisplayObjectContainer.js.map +1 -1
- package/dist/kurot/display/Graphics.d.ts +0 -1
- package/dist/kurot/display/Graphics.d.ts.map +1 -1
- package/dist/kurot/display/Graphics.js +0 -3
- package/dist/kurot/display/Graphics.js.map +1 -1
- package/dist/kurot/display/Mesh.d.ts +9 -3
- package/dist/kurot/display/Mesh.d.ts.map +1 -1
- package/dist/kurot/display/Mesh.js +9 -3
- package/dist/kurot/display/Mesh.js.map +1 -1
- package/dist/kurot/display/Stage.d.ts +0 -1
- package/dist/kurot/display/Stage.d.ts.map +1 -1
- package/dist/kurot/display/Stage.js +0 -2
- package/dist/kurot/display/Stage.js.map +1 -1
- package/dist/kurot/display/enums/BlendMode.d.ts.map +1 -1
- package/dist/kurot/display/enums/BlendMode.js +0 -2
- package/dist/kurot/display/enums/BlendMode.js.map +1 -1
- package/dist/kurot/display/texture/RenderTexture.d.ts +0 -1
- package/dist/kurot/display/texture/RenderTexture.d.ts.map +1 -1
- package/dist/kurot/display/texture/RenderTexture.js +0 -4
- package/dist/kurot/display/texture/RenderTexture.js.map +1 -1
- package/dist/kurot/display/texture/Texture.d.ts +9 -3
- package/dist/kurot/display/texture/Texture.d.ts.map +1 -1
- package/dist/kurot/display/texture/Texture.js +9 -3
- package/dist/kurot/display/texture/Texture.js.map +1 -1
- package/dist/kurot/events/Event.d.ts +3 -1
- package/dist/kurot/events/Event.d.ts.map +1 -1
- package/dist/kurot/events/Event.js +0 -2
- package/dist/kurot/events/Event.js.map +1 -1
- package/dist/kurot/events/EventDispatcher.d.ts.map +1 -1
- package/dist/kurot/events/EventDispatcher.js +0 -2
- package/dist/kurot/events/EventDispatcher.js.map +1 -1
- package/dist/kurot/events/TimerEvent.d.ts +0 -1
- package/dist/kurot/events/TimerEvent.d.ts.map +1 -1
- package/dist/kurot/events/TimerEvent.js +0 -1
- package/dist/kurot/events/TimerEvent.js.map +1 -1
- package/dist/kurot/events/TouchEvent.d.ts +0 -1
- package/dist/kurot/events/TouchEvent.d.ts.map +1 -1
- package/dist/kurot/events/TouchEvent.js +0 -1
- package/dist/kurot/events/TouchEvent.js.map +1 -1
- package/dist/kurot/filters/BlurFilter.d.ts.map +1 -1
- package/dist/kurot/filters/BlurFilter.js +0 -3
- package/dist/kurot/filters/BlurFilter.js.map +1 -1
- package/dist/kurot/filters/DropShadowFilter.d.ts.map +1 -1
- package/dist/kurot/filters/DropShadowFilter.js +0 -2
- package/dist/kurot/filters/DropShadowFilter.js.map +1 -1
- package/dist/kurot/geom/Matrix.d.ts +3 -9
- package/dist/kurot/geom/Matrix.d.ts.map +1 -1
- package/dist/kurot/geom/Matrix.js +3 -9
- package/dist/kurot/geom/Matrix.js.map +1 -1
- package/dist/kurot/geom/Point.d.ts +3 -1
- package/dist/kurot/geom/Point.d.ts.map +1 -1
- package/dist/kurot/geom/Point.js +3 -1
- package/dist/kurot/geom/Point.js.map +1 -1
- package/dist/kurot/geom/Rectangle.d.ts +3 -3
- package/dist/kurot/geom/Rectangle.d.ts.map +1 -1
- package/dist/kurot/geom/Rectangle.js +3 -3
- package/dist/kurot/geom/Rectangle.js.map +1 -1
- package/dist/kurot/media/Sound.d.ts.map +1 -1
- package/dist/kurot/media/Sound.js +1 -8
- package/dist/kurot/media/Sound.js.map +1 -1
- package/dist/kurot/media/SoundChannel.d.ts +0 -1
- package/dist/kurot/media/SoundChannel.d.ts.map +1 -1
- package/dist/kurot/media/SoundChannel.js +0 -3
- package/dist/kurot/media/SoundChannel.js.map +1 -1
- package/dist/kurot/player/InstructionSet.d.ts +4 -17
- package/dist/kurot/player/InstructionSet.d.ts.map +1 -1
- package/dist/kurot/player/InstructionSet.js +3 -20
- package/dist/kurot/player/InstructionSet.js.map +1 -1
- package/dist/kurot/player/KurotOptions.d.ts +24 -9
- package/dist/kurot/player/KurotOptions.d.ts.map +1 -1
- package/dist/kurot/player/Player.d.ts +15 -9
- package/dist/kurot/player/Player.d.ts.map +1 -1
- package/dist/kurot/player/Player.js +20 -22
- package/dist/kurot/player/Player.js.map +1 -1
- package/dist/kurot/player/RenderBuffer.d.ts +4 -14
- package/dist/kurot/player/RenderBuffer.d.ts.map +1 -1
- package/dist/kurot/player/RenderContext.d.ts +11 -27
- package/dist/kurot/player/RenderContext.d.ts.map +1 -1
- package/dist/kurot/player/RenderPipe.d.ts +3 -13
- package/dist/kurot/player/RenderPipe.d.ts.map +1 -1
- package/dist/kurot/player/ScreenAdapter.d.ts +6 -5
- package/dist/kurot/player/ScreenAdapter.d.ts.map +1 -1
- package/dist/kurot/player/ScreenAdapter.js +6 -15
- package/dist/kurot/player/ScreenAdapter.js.map +1 -1
- package/dist/kurot/player/SystemTicker.d.ts +13 -9
- package/dist/kurot/player/SystemTicker.d.ts.map +1 -1
- package/dist/kurot/player/SystemTicker.js +10 -13
- package/dist/kurot/player/SystemTicker.js.map +1 -1
- package/dist/kurot/player/TouchHandler.d.ts +3 -4
- package/dist/kurot/player/TouchHandler.d.ts.map +1 -1
- package/dist/kurot/player/TouchHandler.js +3 -12
- package/dist/kurot/player/TouchHandler.js.map +1 -1
- package/dist/kurot/player/canvas/CanvasBuffer.d.ts.map +1 -1
- package/dist/kurot/player/canvas/CanvasBuffer.js +0 -3
- package/dist/kurot/player/canvas/CanvasBuffer.js.map +1 -1
- package/dist/kurot/player/canvas/CanvasRenderer.d.ts +9 -17
- package/dist/kurot/player/canvas/CanvasRenderer.d.ts.map +1 -1
- package/dist/kurot/player/canvas/CanvasRenderer.js +182 -74
- package/dist/kurot/player/canvas/CanvasRenderer.js.map +1 -1
- package/dist/kurot/player/canvas/DisplayList.d.ts +1 -5
- package/dist/kurot/player/canvas/DisplayList.d.ts.map +1 -1
- package/dist/kurot/player/canvas/DisplayList.js +1 -5
- package/dist/kurot/player/canvas/DisplayList.js.map +1 -1
- package/dist/kurot/player/createPlayer.d.ts.map +1 -1
- package/dist/kurot/player/createPlayer.js +0 -2
- package/dist/kurot/player/createPlayer.js.map +1 -1
- package/dist/kurot/player/pipes/BitmapPipe.d.ts +3 -9
- package/dist/kurot/player/pipes/BitmapPipe.d.ts.map +1 -1
- package/dist/kurot/player/pipes/BitmapPipe.js +19 -33
- package/dist/kurot/player/pipes/BitmapPipe.js.map +1 -1
- package/dist/kurot/player/pipes/FilterPipe.d.ts +11 -28
- package/dist/kurot/player/pipes/FilterPipe.d.ts.map +1 -1
- package/dist/kurot/player/pipes/FilterPipe.js +8 -51
- package/dist/kurot/player/pipes/FilterPipe.js.map +1 -1
- package/dist/kurot/player/pipes/GraphicsPipe.d.ts +2 -7
- package/dist/kurot/player/pipes/GraphicsPipe.d.ts.map +1 -1
- package/dist/kurot/player/pipes/GraphicsPipe.js +28 -38
- package/dist/kurot/player/pipes/GraphicsPipe.js.map +1 -1
- package/dist/kurot/player/pipes/MaskPipe.d.ts +9 -14
- package/dist/kurot/player/pipes/MaskPipe.d.ts.map +1 -1
- package/dist/kurot/player/pipes/MaskPipe.js +24 -46
- package/dist/kurot/player/pipes/MaskPipe.js.map +1 -1
- package/dist/kurot/player/pipes/MeshPipe.d.ts +4 -1
- package/dist/kurot/player/pipes/MeshPipe.d.ts.map +1 -1
- package/dist/kurot/player/pipes/MeshPipe.js +20 -22
- package/dist/kurot/player/pipes/MeshPipe.js.map +1 -1
- package/dist/kurot/player/pipes/ParticlePipe.d.ts +1 -2
- package/dist/kurot/player/pipes/ParticlePipe.d.ts.map +1 -1
- package/dist/kurot/player/pipes/ParticlePipe.js +6 -14
- package/dist/kurot/player/pipes/ParticlePipe.js.map +1 -1
- package/dist/kurot/player/pipes/TextPipe.d.ts +3 -23
- package/dist/kurot/player/pipes/TextPipe.d.ts.map +1 -1
- package/dist/kurot/player/pipes/TextPipe.js +31 -74
- package/dist/kurot/player/pipes/TextPipe.js.map +1 -1
- package/dist/kurot/player/webgl/MultiTextureBatcher.d.ts +1 -12
- package/dist/kurot/player/webgl/MultiTextureBatcher.d.ts.map +1 -1
- package/dist/kurot/player/webgl/MultiTextureBatcher.js +2 -11
- package/dist/kurot/player/webgl/MultiTextureBatcher.js.map +1 -1
- package/dist/kurot/player/webgl/WebGLDrawCmdManager.d.ts +4 -4
- package/dist/kurot/player/webgl/WebGLDrawCmdManager.d.ts.map +1 -1
- package/dist/kurot/player/webgl/WebGLDrawCmdManager.js +11 -10
- package/dist/kurot/player/webgl/WebGLDrawCmdManager.js.map +1 -1
- package/dist/kurot/player/webgl/WebGLProgram.d.ts.map +1 -1
- package/dist/kurot/player/webgl/WebGLProgram.js.map +1 -1
- package/dist/kurot/player/webgl/WebGLRenderBuffer.d.ts +2 -0
- package/dist/kurot/player/webgl/WebGLRenderBuffer.d.ts.map +1 -1
- package/dist/kurot/player/webgl/WebGLRenderBuffer.js +9 -6
- package/dist/kurot/player/webgl/WebGLRenderBuffer.js.map +1 -1
- package/dist/kurot/player/webgl/WebGLRenderContext.d.ts +14 -43
- package/dist/kurot/player/webgl/WebGLRenderContext.d.ts.map +1 -1
- package/dist/kurot/player/webgl/WebGLRenderContext.js +34 -114
- package/dist/kurot/player/webgl/WebGLRenderContext.js.map +1 -1
- package/dist/kurot/player/webgl/WebGLRenderTarget.d.ts +2 -0
- package/dist/kurot/player/webgl/WebGLRenderTarget.d.ts.map +1 -1
- package/dist/kurot/player/webgl/WebGLRenderTarget.js +6 -0
- package/dist/kurot/player/webgl/WebGLRenderTarget.js.map +1 -1
- package/dist/kurot/player/webgl/WebGLRenderer.d.ts +3 -147
- package/dist/kurot/player/webgl/WebGLRenderer.d.ts.map +1 -1
- package/dist/kurot/player/webgl/WebGLRenderer.js +6 -210
- package/dist/kurot/player/webgl/WebGLRenderer.js.map +1 -1
- package/dist/kurot/player/webgl/WebGLUtils.d.ts +4 -4
- package/dist/kurot/player/webgl/WebGLUtils.d.ts.map +1 -1
- package/dist/kurot/player/webgl/WebGLUtils.js +3 -2
- package/dist/kurot/player/webgl/WebGLUtils.js.map +1 -1
- package/dist/kurot/player/webgl/WebGLVertexArrayObject.d.ts +6 -2
- package/dist/kurot/player/webgl/WebGLVertexArrayObject.d.ts.map +1 -1
- package/dist/kurot/player/webgl/WebGLVertexArrayObject.js +6 -11
- package/dist/kurot/player/webgl/WebGLVertexArrayObject.js.map +1 -1
- package/dist/kurot/player/webgl/shaders/ShaderLib.d.ts +1 -2
- package/dist/kurot/player/webgl/shaders/ShaderLib.d.ts.map +1 -1
- package/dist/kurot/player/webgl/shaders/ShaderLib.js +1 -6
- package/dist/kurot/player/webgl/shaders/ShaderLib.js.map +1 -1
- package/dist/kurot/player/webgl/shaders/ShaderLib2.d.ts +1 -2
- package/dist/kurot/player/webgl/shaders/ShaderLib2.d.ts.map +1 -1
- package/dist/kurot/player/webgl/shaders/ShaderLib2.js +1 -13
- package/dist/kurot/player/webgl/shaders/ShaderLib2.js.map +1 -1
- package/dist/kurot/player/webgl/shaders/index.d.ts.map +1 -1
- package/dist/kurot/player/webgl/shaders/index.js +0 -2
- package/dist/kurot/player/webgl/shaders/index.js.map +1 -1
- package/dist/kurot/resource/Resource.d.ts +1 -1
- package/dist/kurot/resource/Resource.d.ts.map +1 -1
- package/dist/kurot/resource/Resource.js +1 -12
- package/dist/kurot/resource/Resource.js.map +1 -1
- package/dist/kurot/resource/ResourceEvent.d.ts +15 -5
- package/dist/kurot/resource/ResourceEvent.d.ts.map +1 -1
- package/dist/kurot/resource/ResourceLoader.d.ts +15 -24
- package/dist/kurot/resource/ResourceLoader.d.ts.map +1 -1
- package/dist/kurot/resource/ResourceLoader.js +17 -35
- package/dist/kurot/resource/ResourceLoader.js.map +1 -1
- package/dist/kurot/resource/analyzers/AnalyzerBase.d.ts +3 -4
- package/dist/kurot/resource/analyzers/AnalyzerBase.d.ts.map +1 -1
- package/dist/kurot/resource/analyzers/AnalyzerBase.js +3 -5
- package/dist/kurot/resource/analyzers/AnalyzerBase.js.map +1 -1
- package/dist/kurot/resource/analyzers/ImageAnalyzer.d.ts.map +1 -1
- package/dist/kurot/resource/analyzers/ImageAnalyzer.js +0 -1
- package/dist/kurot/resource/analyzers/ImageAnalyzer.js.map +1 -1
- package/dist/kurot/resource/analyzers/SheetAnalyzer.d.ts +6 -5
- package/dist/kurot/resource/analyzers/SheetAnalyzer.d.ts.map +1 -1
- package/dist/kurot/resource/analyzers/SheetAnalyzer.js +6 -12
- package/dist/kurot/resource/analyzers/SheetAnalyzer.js.map +1 -1
- package/dist/kurot/resource/analyzers/SoundAnalyzer.d.ts.map +1 -1
- package/dist/kurot/resource/analyzers/SoundAnalyzer.js +0 -1
- package/dist/kurot/resource/analyzers/SoundAnalyzer.js.map +1 -1
- package/dist/kurot/resource/index.d.ts.map +1 -1
- package/dist/kurot/resource/index.js +0 -3
- package/dist/kurot/resource/index.js.map +1 -1
- package/dist/kurot/system/Capabilities.d.ts +11 -13
- package/dist/kurot/system/Capabilities.d.ts.map +1 -1
- package/dist/kurot/system/Capabilities.js +12 -18
- package/dist/kurot/system/Capabilities.js.map +1 -1
- package/dist/kurot/text/BitmapFont.d.ts +0 -1
- package/dist/kurot/text/BitmapFont.d.ts.map +1 -1
- package/dist/kurot/text/BitmapFont.js +0 -2
- package/dist/kurot/text/BitmapFont.js.map +1 -1
- package/dist/kurot/text/BitmapText.d.ts +0 -5
- package/dist/kurot/text/BitmapText.d.ts.map +1 -1
- package/dist/kurot/text/BitmapText.js +0 -6
- package/dist/kurot/text/BitmapText.js.map +1 -1
- package/dist/kurot/text/HtmlTextParser.d.ts +3 -1
- package/dist/kurot/text/HtmlTextParser.d.ts.map +1 -1
- package/dist/kurot/text/HtmlTextParser.js +3 -1
- package/dist/kurot/text/HtmlTextParser.js.map +1 -1
- package/dist/kurot/text/InputController.d.ts.map +1 -1
- package/dist/kurot/text/InputController.js +0 -2
- package/dist/kurot/text/InputController.js.map +1 -1
- package/dist/kurot/text/StageText.d.ts +1 -20
- package/dist/kurot/text/StageText.d.ts.map +1 -1
- package/dist/kurot/text/StageText.js +2 -46
- package/dist/kurot/text/StageText.js.map +1 -1
- package/dist/kurot/text/TextField.d.ts +0 -12
- package/dist/kurot/text/TextField.d.ts.map +1 -1
- package/dist/kurot/text/TextField.js +0 -41
- package/dist/kurot/text/TextField.js.map +1 -1
- package/dist/kurot/text/WordWrap.d.ts +0 -1
- package/dist/kurot/text/WordWrap.d.ts.map +1 -1
- package/dist/kurot/text/WordWrap.js +0 -3
- package/dist/kurot/text/WordWrap.js.map +1 -1
- package/dist/kurot/utils/Base64Util.d.ts +1 -6
- package/dist/kurot/utils/Base64Util.d.ts.map +1 -1
- package/dist/kurot/utils/Base64Util.js +1 -7
- package/dist/kurot/utils/Base64Util.js.map +1 -1
- package/dist/kurot/utils/DebugLog.js +0 -1
- package/dist/kurot/utils/DebugLog.js.map +1 -1
- package/dist/kurot/utils/FontManager.d.ts.map +1 -1
- package/dist/kurot/utils/FontManager.js +3 -1
- package/dist/kurot/utils/FontManager.js.map +1 -1
- package/dist/kurot/utils/NumberUtils.d.ts.map +1 -1
- package/dist/kurot/utils/NumberUtils.js +0 -1
- package/dist/kurot/utils/NumberUtils.js.map +1 -1
- package/package.json +14 -3
- package/dist/kurot/benchmark/BenchmarkRunner.d.ts +0 -60
- package/dist/kurot/benchmark/BenchmarkRunner.d.ts.map +0 -1
- package/dist/kurot/benchmark/BenchmarkRunner.js +0 -112
- package/dist/kurot/benchmark/BenchmarkRunner.js.map +0 -1
- package/dist/kurot/benchmark/MetricsCollector.d.ts +0 -34
- package/dist/kurot/benchmark/MetricsCollector.d.ts.map +0 -1
- package/dist/kurot/benchmark/MetricsCollector.js +0 -123
- package/dist/kurot/benchmark/MetricsCollector.js.map +0 -1
- package/dist/kurot/benchmark/PerfPanel.d.ts +0 -24
- package/dist/kurot/benchmark/PerfPanel.d.ts.map +0 -1
- package/dist/kurot/benchmark/PerfPanel.js +0 -131
- package/dist/kurot/benchmark/PerfPanel.js.map +0 -1
- package/dist/kurot/benchmark/ReportExporter.d.ts +0 -8
- package/dist/kurot/benchmark/ReportExporter.d.ts.map +0 -1
- package/dist/kurot/benchmark/ReportExporter.js +0 -54
- package/dist/kurot/benchmark/ReportExporter.js.map +0 -1
- package/dist/kurot/benchmark/SceneRegistry.d.ts +0 -16
- package/dist/kurot/benchmark/SceneRegistry.d.ts.map +0 -1
- package/dist/kurot/benchmark/SceneRegistry.js +0 -233
- package/dist/kurot/benchmark/SceneRegistry.js.map +0 -1
- package/dist/kurot/benchmark/types.d.ts +0 -47
- package/dist/kurot/benchmark/types.d.ts.map +0 -1
- package/dist/kurot/benchmark/types.js +0 -2
- package/dist/kurot/benchmark/types.js.map +0 -1
|
@@ -11,7 +11,7 @@ import { TextFieldType } from '../../text/enums/TextFieldType.js';
|
|
|
11
11
|
import { getFontString } from '../../text/TextMeasurer.js';
|
|
12
12
|
import { CanvasBuffer, hitTestBuffer } from './CanvasBuffer.js';
|
|
13
13
|
const CAPS_MAP = { none: 'butt', square: 'square', round: 'round' };
|
|
14
|
-
|
|
14
|
+
const CANVAS_BLUR_RADIUS_SCALE = 0.25;
|
|
15
15
|
function colorToString(color) {
|
|
16
16
|
const r = (color >> 16) & 0xff;
|
|
17
17
|
const g = (color >> 8) & 0xff;
|
|
@@ -19,30 +19,22 @@ function colorToString(color) {
|
|
|
19
19
|
return `rgb(${r},${g},${b})`;
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
23
|
-
* using the Canvas 2D API. Equivalent to Egret's `CanvasRenderer`.
|
|
24
|
-
*
|
|
25
|
-
* Performance notes:
|
|
26
|
-
* - Currently does full-tree traversal and full-canvas redraw every frame.
|
|
27
|
-
* Egret used a DisplayList with dirty-region tracking to only redraw changed areas.
|
|
28
|
-
* This should be added when performance becomes a concern.
|
|
29
|
-
* - Egret used a RenderNode intermediate layer (BitmapNode, GraphicsNode, etc.)
|
|
30
|
-
* to cache rendering instructions. Kurot reads DisplayObject data directly,
|
|
31
|
-
* which is simpler but skips the caching benefit. If profiling shows the JS-side
|
|
32
|
-
* traversal is a bottleneck, consider adding a lightweight render command cache.
|
|
33
|
-
* - For high-performance scenarios, a WebGL renderer with batch rendering should
|
|
34
|
-
* be implemented as an alternative backend.
|
|
22
|
+
* Traverses a display-object tree and renders it with Canvas 2D.
|
|
35
23
|
*/
|
|
36
24
|
export class CanvasRenderer {
|
|
37
25
|
// ── Instance fields ───────────────────────────────────────────────────────
|
|
38
26
|
_hasFill = false;
|
|
39
27
|
_hasStroke = false;
|
|
28
|
+
_bitmapTintCache = new WeakMap();
|
|
29
|
+
_graphicsTintCache = new WeakMap();
|
|
30
|
+
_globalTint = 0xffffff;
|
|
40
31
|
// ── Public methods ────────────────────────────────────────────────────────
|
|
41
32
|
/**
|
|
42
33
|
* Renders a display object tree into the given buffer.
|
|
43
34
|
*/
|
|
44
35
|
render(displayObject, buffer, matrix) {
|
|
45
36
|
const ctx = buffer.context;
|
|
37
|
+
this._globalTint = 0xffffff;
|
|
46
38
|
if (matrix) {
|
|
47
39
|
ctx.save();
|
|
48
40
|
ctx.transform(matrix.a, matrix.b, matrix.c, matrix.d, matrix.tx, matrix.ty);
|
|
@@ -52,26 +44,21 @@ export class CanvasRenderer {
|
|
|
52
44
|
ctx.restore();
|
|
53
45
|
return drawCalls;
|
|
54
46
|
}
|
|
55
|
-
/** @internal Used by WebGLRenderer for offscreen DisplayList rendering. */
|
|
56
47
|
renderToContext(displayObject, ctx, offsetX, offsetY) {
|
|
57
48
|
this.drawDisplayObject(displayObject, ctx, offsetX, offsetY, true);
|
|
58
49
|
}
|
|
59
|
-
/** @internal Used by WebGLRenderer to rasterize a Graphics object into a Canvas 2D context. */
|
|
60
50
|
renderGraphicsToContext(graphics, ctx, offsetX, offsetY, forHitTest = false, skipCache = false) {
|
|
61
51
|
this.renderGraphics(graphics, ctx, offsetX, offsetY, forHitTest, skipCache);
|
|
62
52
|
}
|
|
63
|
-
/** @internal Used by WebGL TextPipe to rasterize a TextField into a Canvas 2D context. */
|
|
64
53
|
renderTextFieldToContext(tf, ctx, offsetX, offsetY) {
|
|
65
54
|
this.renderTextField(tf, ctx, offsetX, offsetY);
|
|
66
55
|
}
|
|
67
|
-
/** @internal Used by Bitmap pixel hit test. */
|
|
68
56
|
renderBitmapToContext(bitmap, ctx, offsetX, offsetY) {
|
|
69
57
|
this.renderBitmap(bitmap, ctx, offsetX, offsetY);
|
|
70
58
|
}
|
|
71
59
|
// ── Private: tree traversal ───────────────────────────────────────────────
|
|
72
60
|
drawDisplayObject(displayObject, ctx, offsetX, offsetY, _isStage = false) {
|
|
73
61
|
let drawCalls = 0;
|
|
74
|
-
// DisplayList cache (cacheAsBitmap)
|
|
75
62
|
const $displayList = displayObject.$displayList;
|
|
76
63
|
if ($displayList && !_isStage) {
|
|
77
64
|
if (displayObject.$cacheDirty || displayObject.$renderDirty) {
|
|
@@ -85,7 +72,6 @@ export class CanvasRenderer {
|
|
|
85
72
|
displayObject.$cacheDirty = false;
|
|
86
73
|
displayObject.$renderDirty = false;
|
|
87
74
|
}
|
|
88
|
-
// Draw cached result and skip $children
|
|
89
75
|
if ($displayList.bitmapData?.source) {
|
|
90
76
|
const resolution = $displayList.actualResolution;
|
|
91
77
|
const previousSmoothing = ctx.imageSmoothingEnabled;
|
|
@@ -96,9 +82,7 @@ export class CanvasRenderer {
|
|
|
96
82
|
}
|
|
97
83
|
return drawCalls;
|
|
98
84
|
}
|
|
99
|
-
// Draw self
|
|
100
85
|
drawCalls += this.renderSelf(displayObject, ctx, offsetX, offsetY);
|
|
101
|
-
// Draw $children
|
|
102
86
|
const $children = displayObject.$children;
|
|
103
87
|
if (!$children)
|
|
104
88
|
return drawCalls;
|
|
@@ -106,6 +90,10 @@ export class CanvasRenderer {
|
|
|
106
90
|
const child = $children[i];
|
|
107
91
|
if (child.$renderMode === 1 /* RenderMode.NONE */)
|
|
108
92
|
continue;
|
|
93
|
+
const previousTint = this._globalTint;
|
|
94
|
+
if (child.$tintRGB !== 0xffffff) {
|
|
95
|
+
this._globalTint = child.tint;
|
|
96
|
+
}
|
|
109
97
|
let childOffsetX;
|
|
110
98
|
let childOffsetY;
|
|
111
99
|
if (child.$useTranslate) {
|
|
@@ -144,6 +132,7 @@ export class CanvasRenderer {
|
|
|
144
132
|
else if (prevAlpha !== undefined) {
|
|
145
133
|
ctx.globalAlpha = prevAlpha;
|
|
146
134
|
}
|
|
135
|
+
this._globalTint = previousTint;
|
|
147
136
|
}
|
|
148
137
|
return drawCalls;
|
|
149
138
|
}
|
|
@@ -170,15 +159,11 @@ export class CanvasRenderer {
|
|
|
170
159
|
const bounds = displayObject.$getOriginalBounds();
|
|
171
160
|
if (bounds.width <= 0 || bounds.height <= 0)
|
|
172
161
|
return 0;
|
|
173
|
-
// Build CSS filter string for GPU-accelerated filters.
|
|
174
|
-
// ColorMatrixFilter cannot be expressed as a CSS filter string (arbitrary matrix),
|
|
175
|
-
// so it falls back to the CPU pixel path below.
|
|
176
162
|
const cssFilters = [];
|
|
177
163
|
let hasCpuFilter = false;
|
|
178
164
|
for (const filter of filters) {
|
|
179
165
|
if (filter instanceof BlurFilter) {
|
|
180
|
-
|
|
181
|
-
const radius = (filter.blurX + filter.blurY) / 2;
|
|
166
|
+
const radius = ((filter.blurX + filter.blurY) / 2) * CANVAS_BLUR_RADIUS_SCALE;
|
|
182
167
|
if (radius > 0)
|
|
183
168
|
cssFilters.push(`blur(${radius}px)`);
|
|
184
169
|
}
|
|
@@ -194,7 +179,6 @@ export class CanvasRenderer {
|
|
|
194
179
|
cssFilters.push(`drop-shadow(${dx}px ${dy}px ${blur}px rgba(${r},${g},${b},${a / 255}))`);
|
|
195
180
|
}
|
|
196
181
|
else if (filter instanceof GlowFilter) {
|
|
197
|
-
// Approximate glow as a zero-offset drop-shadow.
|
|
198
182
|
const blur = (filter.blurX + filter.blurY) / 2;
|
|
199
183
|
const r = (filter.color >> 16) & 0xff;
|
|
200
184
|
const g = (filter.color >> 8) & 0xff;
|
|
@@ -231,7 +215,6 @@ export class CanvasRenderer {
|
|
|
231
215
|
const bufferH = Math.ceil(bounds.height);
|
|
232
216
|
const offscreen = new CanvasBuffer(bufferW, bufferH);
|
|
233
217
|
const offCtx = offscreen.context;
|
|
234
|
-
// Apply CSS-capable filters on the offscreen context before drawing.
|
|
235
218
|
if (cssFilters.length > 0)
|
|
236
219
|
offCtx.filter = cssFilters.join(' ');
|
|
237
220
|
let drawCalls = 0;
|
|
@@ -249,7 +232,6 @@ export class CanvasRenderer {
|
|
|
249
232
|
return 0;
|
|
250
233
|
}
|
|
251
234
|
offCtx.filter = 'none';
|
|
252
|
-
// Apply CPU-only filters (ColorMatrixFilter).
|
|
253
235
|
const imageData = offCtx.getImageData(0, 0, offscreen.width, offscreen.height);
|
|
254
236
|
const data = imageData.data;
|
|
255
237
|
for (const filter of filters) {
|
|
@@ -279,8 +261,6 @@ export class CanvasRenderer {
|
|
|
279
261
|
ctx.rect(scrollRect.x + offsetX, scrollRect.y + offsetY, scrollRect.width, scrollRect.height);
|
|
280
262
|
ctx.clip();
|
|
281
263
|
}
|
|
282
|
-
// DisplayObject mask: render content and mask to offscreen buffers,
|
|
283
|
-
// composite with 'destination-in' to produce the masked result.
|
|
284
264
|
if (mask) {
|
|
285
265
|
const bounds = displayObject.$getOriginalBounds();
|
|
286
266
|
if (bounds.width <= 0 || bounds.height <= 0) {
|
|
@@ -294,15 +274,12 @@ export class CanvasRenderer {
|
|
|
294
274
|
const bh = Math.ceil(bounds.height);
|
|
295
275
|
const bx = bounds.x;
|
|
296
276
|
const by = bounds.y;
|
|
297
|
-
// Render content to offscreen buffer
|
|
298
277
|
const contentBuffer = new CanvasBuffer(bw, bh);
|
|
299
278
|
const contentCtx = contentBuffer.context;
|
|
300
279
|
const drawCalls = this.drawDisplayObject(displayObject, contentCtx, -bx, -by);
|
|
301
|
-
// Render mask shape to the same buffer using destination-in
|
|
302
280
|
contentCtx.globalCompositeOperation = 'destination-in';
|
|
303
281
|
const maskMatrix = mask.$getConcatenatedMatrix();
|
|
304
282
|
const parentMatrix = displayObject.$getConcatenatedMatrix();
|
|
305
|
-
// Transform mask relative to the content's local space
|
|
306
283
|
contentCtx.save();
|
|
307
284
|
const invA = parentMatrix.a, invB = parentMatrix.b, invC = parentMatrix.c, invD = parentMatrix.d;
|
|
308
285
|
const invTx = parentMatrix.tx, invTy = parentMatrix.ty;
|
|
@@ -311,7 +288,6 @@ export class CanvasRenderer {
|
|
|
311
288
|
const ia = invD / det, ib = -invB / det, ic = -invC / det, id = invA / det;
|
|
312
289
|
const itx = (invC * invTy - invD * invTx) / det;
|
|
313
290
|
const ity = (invB * invTx - invA * invTy) / det;
|
|
314
|
-
// Combine: inverse(parent) * mask
|
|
315
291
|
const ra = ia * maskMatrix.a + ic * maskMatrix.b;
|
|
316
292
|
const rb = ib * maskMatrix.a + id * maskMatrix.b;
|
|
317
293
|
const rc = ia * maskMatrix.c + ic * maskMatrix.d;
|
|
@@ -326,7 +302,6 @@ export class CanvasRenderer {
|
|
|
326
302
|
this.drawDisplayObject(mask, contentCtx, 0, 0);
|
|
327
303
|
contentCtx.restore();
|
|
328
304
|
contentCtx.globalCompositeOperation = 'source-over';
|
|
329
|
-
// Draw the masked result onto the main context
|
|
330
305
|
ctx.drawImage(contentBuffer.surface, offsetX + bx, offsetY + by);
|
|
331
306
|
contentBuffer.destroy();
|
|
332
307
|
if (scrollRect)
|
|
@@ -363,13 +338,31 @@ export class CanvasRenderer {
|
|
|
363
338
|
}
|
|
364
339
|
renderMesh(mesh, ctx, offsetX, offsetY) {
|
|
365
340
|
const bd = mesh.bitmapData;
|
|
366
|
-
if (!bd?.source || mesh.vertices.length === 0)
|
|
341
|
+
if (!bd?.source || mesh.vertices.length === 0 || mesh.uvs.length !== mesh.vertices.length)
|
|
367
342
|
return 0;
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
343
|
+
const tinted = this._globalTint !== 0xffffff;
|
|
344
|
+
const source = tinted
|
|
345
|
+
? this.getTintedBitmapSource(mesh, this._globalTint)
|
|
346
|
+
: bd.source;
|
|
347
|
+
const sourceX = tinted ? 0 : mesh.bitmapX;
|
|
348
|
+
const sourceY = tinted ? 0 : mesh.bitmapY;
|
|
349
|
+
const sourceWidth = mesh.bitmapWidth;
|
|
350
|
+
const sourceHeight = mesh.bitmapHeight;
|
|
351
|
+
ctx.imageSmoothingEnabled = mesh.smoothing;
|
|
352
|
+
for (let i = 0; i + 2 < mesh.indices.length; i += 3) {
|
|
353
|
+
const i0 = mesh.indices[i];
|
|
354
|
+
const i1 = mesh.indices[i + 1];
|
|
355
|
+
const i2 = mesh.indices[i + 2];
|
|
356
|
+
if (i0 < 0 ||
|
|
357
|
+
i1 < 0 ||
|
|
358
|
+
i2 < 0 ||
|
|
359
|
+
i0 * 2 + 1 >= mesh.vertices.length ||
|
|
360
|
+
i1 * 2 + 1 >= mesh.vertices.length ||
|
|
361
|
+
i2 * 2 + 1 >= mesh.vertices.length) {
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
this.drawTexturedTriangle(ctx, source, sourceX, sourceY, sourceWidth, sourceHeight, mesh.vertices, mesh.uvs, i0, i1, i2, offsetX + mesh.bitmapOffsetX, offsetY + mesh.bitmapOffsetY);
|
|
365
|
+
}
|
|
373
366
|
return 1;
|
|
374
367
|
}
|
|
375
368
|
renderBitmap(bitmap, ctx, offsetX, offsetY) {
|
|
@@ -381,21 +374,157 @@ export class CanvasRenderer {
|
|
|
381
374
|
if (destW <= 0 || destH <= 0)
|
|
382
375
|
return 0;
|
|
383
376
|
ctx.imageSmoothingEnabled = bitmap.smoothing;
|
|
384
|
-
|
|
377
|
+
if (this._globalTint === 0xffffff) {
|
|
378
|
+
ctx.drawImage(bd.source, bitmap.bitmapX, bitmap.bitmapY, bitmap.bitmapWidth, bitmap.bitmapHeight, offsetX + bitmap.bitmapOffsetX, offsetY + bitmap.bitmapOffsetY, destW, destH);
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
ctx.drawImage(this.getTintedBitmapSource(bitmap, this._globalTint), offsetX + bitmap.bitmapOffsetX, offsetY + bitmap.bitmapOffsetY, destW, destH);
|
|
382
|
+
}
|
|
385
383
|
return 1;
|
|
386
384
|
}
|
|
385
|
+
getTintedBitmapSource(bitmap, tint) {
|
|
386
|
+
const bitmapData = bitmap.bitmapData;
|
|
387
|
+
let cache = this._bitmapTintCache.get(bitmap);
|
|
388
|
+
const needsUpdate = !cache ||
|
|
389
|
+
cache.tint !== tint ||
|
|
390
|
+
cache.contentVersion !== bitmapData.contentVersion ||
|
|
391
|
+
cache.sourceX !== bitmap.bitmapX ||
|
|
392
|
+
cache.sourceY !== bitmap.bitmapY ||
|
|
393
|
+
cache.sourceWidth !== bitmap.bitmapWidth ||
|
|
394
|
+
cache.sourceHeight !== bitmap.bitmapHeight;
|
|
395
|
+
if (!cache) {
|
|
396
|
+
cache = this.createTintedCanvasCache();
|
|
397
|
+
this._bitmapTintCache.set(bitmap, cache);
|
|
398
|
+
}
|
|
399
|
+
if (needsUpdate) {
|
|
400
|
+
this.updateTintedCanvas(cache, bitmapData.source, bitmap.bitmapX, bitmap.bitmapY, bitmap.bitmapWidth, bitmap.bitmapHeight, tint, bitmapData.contentVersion);
|
|
401
|
+
}
|
|
402
|
+
return cache.buffer.surface;
|
|
403
|
+
}
|
|
404
|
+
getTintedGraphicsSource(graphics, tint, sourceChanged) {
|
|
405
|
+
const source = graphics.offscreenCanvas;
|
|
406
|
+
let cache = this._graphicsTintCache.get(graphics);
|
|
407
|
+
const needsUpdate = sourceChanged ||
|
|
408
|
+
!cache ||
|
|
409
|
+
cache.tint !== tint ||
|
|
410
|
+
cache.sourceWidth !== source.width ||
|
|
411
|
+
cache.sourceHeight !== source.height;
|
|
412
|
+
if (!cache) {
|
|
413
|
+
cache = this.createTintedCanvasCache();
|
|
414
|
+
this._graphicsTintCache.set(graphics, cache);
|
|
415
|
+
}
|
|
416
|
+
if (needsUpdate) {
|
|
417
|
+
this.updateTintedCanvas(cache, source, 0, 0, source.width, source.height, tint, cache.contentVersion + 1);
|
|
418
|
+
}
|
|
419
|
+
return cache.buffer.surface;
|
|
420
|
+
}
|
|
421
|
+
createTintedCanvasCache() {
|
|
422
|
+
return {
|
|
423
|
+
buffer: new CanvasBuffer(),
|
|
424
|
+
tint: 0xffffff,
|
|
425
|
+
contentVersion: -1,
|
|
426
|
+
sourceX: 0,
|
|
427
|
+
sourceY: 0,
|
|
428
|
+
sourceWidth: 0,
|
|
429
|
+
sourceHeight: 0,
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
updateTintedCanvas(cache, source, sourceX, sourceY, sourceWidth, sourceHeight, tint, contentVersion) {
|
|
433
|
+
const width = Math.max(1, Math.ceil(sourceWidth));
|
|
434
|
+
const height = Math.max(1, Math.ceil(sourceHeight));
|
|
435
|
+
if (cache.buffer.width !== width || cache.buffer.height !== height) {
|
|
436
|
+
cache.buffer.resize(width, height);
|
|
437
|
+
}
|
|
438
|
+
else {
|
|
439
|
+
cache.buffer.clear();
|
|
440
|
+
}
|
|
441
|
+
const context = cache.buffer.context;
|
|
442
|
+
context.drawImage(source, sourceX, sourceY, sourceWidth, sourceHeight, 0, 0, width, height);
|
|
443
|
+
context.globalCompositeOperation = 'multiply';
|
|
444
|
+
context.fillStyle = colorToString(tint);
|
|
445
|
+
context.fillRect(0, 0, width, height);
|
|
446
|
+
context.globalCompositeOperation = 'destination-in';
|
|
447
|
+
context.drawImage(source, sourceX, sourceY, sourceWidth, sourceHeight, 0, 0, width, height);
|
|
448
|
+
context.globalCompositeOperation = 'source-over';
|
|
449
|
+
cache.tint = tint;
|
|
450
|
+
cache.contentVersion = contentVersion;
|
|
451
|
+
cache.sourceX = sourceX;
|
|
452
|
+
cache.sourceY = sourceY;
|
|
453
|
+
cache.sourceWidth = sourceWidth;
|
|
454
|
+
cache.sourceHeight = sourceHeight;
|
|
455
|
+
}
|
|
456
|
+
drawTexturedTriangle(ctx, source, sourceX, sourceY, sourceWidth, sourceHeight, vertices, uvs, i0, i1, i2, offsetX, offsetY) {
|
|
457
|
+
const sx0 = sourceX + uvs[i0 * 2] * sourceWidth;
|
|
458
|
+
const sy0 = sourceY + uvs[i0 * 2 + 1] * sourceHeight;
|
|
459
|
+
const sx1 = sourceX + uvs[i1 * 2] * sourceWidth;
|
|
460
|
+
const sy1 = sourceY + uvs[i1 * 2 + 1] * sourceHeight;
|
|
461
|
+
const sx2 = sourceX + uvs[i2 * 2] * sourceWidth;
|
|
462
|
+
const sy2 = sourceY + uvs[i2 * 2 + 1] * sourceHeight;
|
|
463
|
+
const dx0 = offsetX + vertices[i0 * 2];
|
|
464
|
+
const dy0 = offsetY + vertices[i0 * 2 + 1];
|
|
465
|
+
const dx1 = offsetX + vertices[i1 * 2];
|
|
466
|
+
const dy1 = offsetY + vertices[i1 * 2 + 1];
|
|
467
|
+
const dx2 = offsetX + vertices[i2 * 2];
|
|
468
|
+
const dy2 = offsetY + vertices[i2 * 2 + 1];
|
|
469
|
+
const determinant = sx0 * (sy1 - sy2) + sx1 * (sy2 - sy0) + sx2 * (sy0 - sy1);
|
|
470
|
+
if (Math.abs(determinant) <= Number.EPSILON)
|
|
471
|
+
return;
|
|
472
|
+
const a = (dx0 * (sy1 - sy2) + dx1 * (sy2 - sy0) + dx2 * (sy0 - sy1)) / determinant;
|
|
473
|
+
const b = (dy0 * (sy1 - sy2) + dy1 * (sy2 - sy0) + dy2 * (sy0 - sy1)) / determinant;
|
|
474
|
+
const c = (dx0 * (sx2 - sx1) + dx1 * (sx0 - sx2) + dx2 * (sx1 - sx0)) / determinant;
|
|
475
|
+
const d = (dy0 * (sx2 - sx1) + dy1 * (sx0 - sx2) + dy2 * (sx1 - sx0)) / determinant;
|
|
476
|
+
const e = (dx0 * (sx1 * sy2 - sx2 * sy1) +
|
|
477
|
+
dx1 * (sx2 * sy0 - sx0 * sy2) +
|
|
478
|
+
dx2 * (sx0 * sy1 - sx1 * sy0)) /
|
|
479
|
+
determinant;
|
|
480
|
+
const f = (dy0 * (sx1 * sy2 - sx2 * sy1) +
|
|
481
|
+
dy1 * (sx2 * sy0 - sx0 * sy2) +
|
|
482
|
+
dy2 * (sx0 * sy1 - sx1 * sy0)) /
|
|
483
|
+
determinant;
|
|
484
|
+
ctx.save();
|
|
485
|
+
const centerX = (dx0 + dx1 + dx2) / 3;
|
|
486
|
+
const centerY = (dy0 + dy1 + dy2) / 3;
|
|
487
|
+
const vx0 = dx0 - centerX;
|
|
488
|
+
const vy0 = dy0 - centerY;
|
|
489
|
+
const vx1 = dx1 - centerX;
|
|
490
|
+
const vy1 = dy1 - centerY;
|
|
491
|
+
const vx2 = dx2 - centerX;
|
|
492
|
+
const vy2 = dy2 - centerY;
|
|
493
|
+
const length0 = Math.hypot(vx0, vy0);
|
|
494
|
+
const length1 = Math.hypot(vx1, vy1);
|
|
495
|
+
const length2 = Math.hypot(vx2, vy2);
|
|
496
|
+
const scale0 = length0 > 0 ? 1 + 0.5 / length0 : 1;
|
|
497
|
+
const scale1 = length1 > 0 ? 1 + 0.5 / length1 : 1;
|
|
498
|
+
const scale2 = length2 > 0 ? 1 + 0.5 / length2 : 1;
|
|
499
|
+
// Slightly overlapping clips prevent transparent antialiasing seams between adjacent triangles.
|
|
500
|
+
const clipX0 = centerX + vx0 * scale0;
|
|
501
|
+
const clipY0 = centerY + vy0 * scale0;
|
|
502
|
+
const clipX1 = centerX + vx1 * scale1;
|
|
503
|
+
const clipY1 = centerY + vy1 * scale1;
|
|
504
|
+
const clipX2 = centerX + vx2 * scale2;
|
|
505
|
+
const clipY2 = centerY + vy2 * scale2;
|
|
506
|
+
ctx.beginPath();
|
|
507
|
+
ctx.moveTo(clipX0, clipY0);
|
|
508
|
+
ctx.lineTo(clipX1, clipY1);
|
|
509
|
+
ctx.lineTo(clipX2, clipY2);
|
|
510
|
+
ctx.closePath();
|
|
511
|
+
ctx.clip();
|
|
512
|
+
ctx.transform(a, b, c, d, e, f);
|
|
513
|
+
ctx.drawImage(source, 0, 0);
|
|
514
|
+
ctx.restore();
|
|
515
|
+
}
|
|
387
516
|
renderGraphics(graphics, ctx, offsetX, offsetY, forHitTest = false, skipCache = false) {
|
|
388
517
|
if (graphics.commands.length === 0)
|
|
389
518
|
return 0;
|
|
390
519
|
// ── Offscreen cache (skip for hit-test or when caller manages its own cache) ──
|
|
391
520
|
if (!forHitTest && !skipCache) {
|
|
521
|
+
let rebuilt = false;
|
|
392
522
|
if (graphics.canvasCacheDirty || !graphics.offscreenCanvas) {
|
|
393
|
-
|
|
523
|
+
rebuilt = true;
|
|
394
524
|
const bounds = new Rectangle();
|
|
395
525
|
graphics.$measureContentBounds(bounds);
|
|
396
526
|
const cw = Math.ceil(bounds.width) || 1;
|
|
397
527
|
const ch = Math.ceil(bounds.height) || 1;
|
|
398
|
-
// Create or resize offscreen canvas
|
|
399
528
|
if (!graphics.offscreenCanvas) {
|
|
400
529
|
graphics.offscreenCanvas = document.createElement('canvas');
|
|
401
530
|
graphics.offscreenCtx = graphics.offscreenCanvas.getContext('2d', { willReadFrequently: true });
|
|
@@ -416,15 +545,16 @@ export class CanvasRenderer {
|
|
|
416
545
|
for (const cmd of graphics.commands) {
|
|
417
546
|
this.executeGraphicsCommand(cmd, oc2d, false);
|
|
418
547
|
}
|
|
419
|
-
// Flush any open path that wasn't closed by endFill
|
|
420
548
|
this.flushOpenPath(oc2d);
|
|
421
549
|
oc2d.restore();
|
|
422
550
|
graphics.offscreenBoundsX = bounds.x;
|
|
423
551
|
graphics.offscreenBoundsY = bounds.y;
|
|
424
552
|
graphics.canvasCacheDirty = false;
|
|
425
553
|
}
|
|
426
|
-
|
|
427
|
-
|
|
554
|
+
const source = this._globalTint === 0xffffff
|
|
555
|
+
? graphics.offscreenCanvas
|
|
556
|
+
: this.getTintedGraphicsSource(graphics, this._globalTint, rebuilt);
|
|
557
|
+
ctx.drawImage(source, offsetX + graphics.offscreenBoundsX, offsetY + graphics.offscreenBoundsY);
|
|
428
558
|
return 1;
|
|
429
559
|
}
|
|
430
560
|
// ── Hit-test path: direct execution, no cache ─────────────────────────
|
|
@@ -435,16 +565,12 @@ export class CanvasRenderer {
|
|
|
435
565
|
for (const cmd of graphics.commands) {
|
|
436
566
|
this.executeGraphicsCommand(cmd, ctx, forHitTest);
|
|
437
567
|
}
|
|
438
|
-
// Flush any open path that wasn't closed by endFill
|
|
439
568
|
this.flushOpenPath(ctx);
|
|
440
569
|
ctx.restore();
|
|
441
570
|
return 1;
|
|
442
571
|
}
|
|
443
572
|
renderTextField(tf, ctx, offsetX, offsetY) {
|
|
444
|
-
tf.getLinesArr();
|
|
445
|
-
// INPUT mode while focused: HTML input element owns the display.
|
|
446
|
-
// Only render background/border so the field is visible, but skip
|
|
447
|
-
// text content to avoid the double-text artefact.
|
|
573
|
+
tf.getLinesArr();
|
|
448
574
|
const inputFocused = tf.type === TextFieldType.INPUT && tf.isTyping;
|
|
449
575
|
const width = !isNaN(tf.$explicitWidth) ? tf.$explicitWidth : tf.textWidth;
|
|
450
576
|
const height = !isNaN(tf.$explicitHeight) ? tf.$explicitHeight : tf.textHeight;
|
|
@@ -463,7 +589,6 @@ export class CanvasRenderer {
|
|
|
463
589
|
ctx.lineWidth = 1;
|
|
464
590
|
ctx.strokeRect(0, 0, width, height);
|
|
465
591
|
}
|
|
466
|
-
// While the native input is active, skip text/cursor rendering.
|
|
467
592
|
if (inputFocused) {
|
|
468
593
|
ctx.restore();
|
|
469
594
|
return 0;
|
|
@@ -490,11 +615,7 @@ export class CanvasRenderer {
|
|
|
490
615
|
}
|
|
491
616
|
// ── ScrollV offset ────────────────────────────────────────────────────
|
|
492
617
|
const scrollOffset = tf.getScrollYOffset();
|
|
493
|
-
// ──
|
|
494
|
-
// Following Egret's TextField.drawText():
|
|
495
|
-
// drawY advances by h/2 before drawing, then h/2 + lineSpacing after.
|
|
496
|
-
// Each element's y = drawY + (lineHeight - elementSize) / 2.
|
|
497
|
-
// With textBaseline='middle', the browser handles vertical centering automatically.
|
|
618
|
+
// ── Text lines ───────────────────────────────────────────────────────────
|
|
498
619
|
let drawY = verticalOffset - scrollOffset;
|
|
499
620
|
let drawCalls = 0;
|
|
500
621
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -505,7 +626,6 @@ export class CanvasRenderer {
|
|
|
505
626
|
drawY += h / 2 + lineSpacing;
|
|
506
627
|
continue;
|
|
507
628
|
}
|
|
508
|
-
// Horizontal alignment offset
|
|
509
629
|
let lineX = 0;
|
|
510
630
|
if (tf.textAlign === HorizontalAlign.RIGHT) {
|
|
511
631
|
lineX = width - line.width;
|
|
@@ -513,7 +633,6 @@ export class CanvasRenderer {
|
|
|
513
633
|
else if (tf.textAlign === HorizontalAlign.CENTER) {
|
|
514
634
|
lineX = (width - line.width) / 2;
|
|
515
635
|
}
|
|
516
|
-
// Draw each element in the line
|
|
517
636
|
for (const el of line.elements) {
|
|
518
637
|
const style = el.style;
|
|
519
638
|
const fontSize = style?.size ?? tf.size;
|
|
@@ -528,7 +647,6 @@ export class CanvasRenderer {
|
|
|
528
647
|
ctx.textBaseline = 'middle';
|
|
529
648
|
ctx.textAlign = 'left';
|
|
530
649
|
const textY = drawY + (h - fontSize) / 2;
|
|
531
|
-
// Stroke
|
|
532
650
|
if (stroke > 0) {
|
|
533
651
|
ctx.strokeStyle = colorToString(strokeColor);
|
|
534
652
|
ctx.lineWidth = stroke * 2;
|
|
@@ -536,7 +654,6 @@ export class CanvasRenderer {
|
|
|
536
654
|
ctx.strokeText(el.text, lineX, textY);
|
|
537
655
|
drawCalls++;
|
|
538
656
|
}
|
|
539
|
-
// Fill
|
|
540
657
|
ctx.fillStyle = colorToString(textColor);
|
|
541
658
|
ctx.fillText(el.text, lineX, textY);
|
|
542
659
|
drawCalls++;
|
|
@@ -546,12 +663,10 @@ export class CanvasRenderer {
|
|
|
546
663
|
}
|
|
547
664
|
// ── INPUT cursor ──────────────────────────────────────────────────────
|
|
548
665
|
if (tf.type === TextFieldType.INPUT && tf.isTyping) {
|
|
549
|
-
// Draw blinking cursor at caretIndex position
|
|
550
666
|
const caretIndex = tf.caretIndex;
|
|
551
667
|
const fontStr = getFontString(tf.size, tf.fontFamily, tf.bold, tf.italic);
|
|
552
668
|
ctx.font = fontStr;
|
|
553
669
|
ctx.textBaseline = 'middle';
|
|
554
|
-
// Calculate cursor x by measuring text up to caretIndex
|
|
555
670
|
let cursorX = 0;
|
|
556
671
|
let charCount = 0;
|
|
557
672
|
for (const line of lines) {
|
|
@@ -568,7 +683,7 @@ export class CanvasRenderer {
|
|
|
568
683
|
}
|
|
569
684
|
if (charCount >= caretIndex)
|
|
570
685
|
break;
|
|
571
|
-
cursorX = 0;
|
|
686
|
+
cursorX = 0;
|
|
572
687
|
}
|
|
573
688
|
const cursorY = verticalOffset - scrollOffset;
|
|
574
689
|
ctx.fillStyle = colorToString(tf.textColor);
|
|
@@ -630,8 +745,6 @@ export class CanvasRenderer {
|
|
|
630
745
|
this._hasFill = true;
|
|
631
746
|
break;
|
|
632
747
|
}
|
|
633
|
-
// createGradientBox uses the Flash/Egret convention where the matrix
|
|
634
|
-
// maps gradient space ±819.2 (1638.4/2) to the desired box edges.
|
|
635
748
|
const GH = 819.2;
|
|
636
749
|
let gradient;
|
|
637
750
|
if (cmd.matrix) {
|
|
@@ -773,15 +886,11 @@ function applyColorMatrix(data, matrix) {
|
|
|
773
886
|
}
|
|
774
887
|
}
|
|
775
888
|
// ── Graphics pixel-perfect hit test ──────────────────────────────────────────
|
|
776
|
-
// Registered here to avoid circular dependency between display/ and player/.
|
|
777
|
-
// Uses the shared 3×3 hitTestBuffer: translate so the test point lands at (1,1),
|
|
778
|
-
// render with forHitTest=true (all shapes drawn as opaque black), then read alpha.
|
|
779
889
|
const _hitRenderer = new CanvasRenderer();
|
|
780
890
|
setGraphicsHitTest((graphics, localX, localY) => {
|
|
781
891
|
const buf = hitTestBuffer();
|
|
782
892
|
buf.clear();
|
|
783
893
|
const ctx = buf.context;
|
|
784
|
-
// Translate so localX/Y maps to pixel (1,1) in the 3×3 buffer
|
|
785
894
|
ctx.setTransform(1, 0, 0, 1, 1 - localX, 1 - localY);
|
|
786
895
|
_hitRenderer.renderGraphicsToContext(graphics, ctx, 0, 0, true);
|
|
787
896
|
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
@@ -793,7 +902,6 @@ setGraphicsHitTest((graphics, localX, localY) => {
|
|
|
793
902
|
}
|
|
794
903
|
});
|
|
795
904
|
// ── Bitmap pixel-perfect hit test ────────────────────────────────────────────
|
|
796
|
-
// Renders the Bitmap into the shared 3×3 buffer at the test point and reads alpha.
|
|
797
905
|
setBitmapPixelHitTest((bitmap, localX, localY) => {
|
|
798
906
|
const buf = hitTestBuffer();
|
|
799
907
|
buf.clear();
|