@lightningjs/renderer 0.6.1 → 0.7.1

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.
Files changed (201) hide show
  1. package/dist/src/common/CommonTypes.d.ts +8 -0
  2. package/dist/src/core/CoreNode.d.ts +4 -7
  3. package/dist/src/core/CoreNode.js +73 -40
  4. package/dist/src/core/CoreNode.js.map +1 -1
  5. package/dist/src/core/CoreTextNode.d.ts +12 -2
  6. package/dist/src/core/CoreTextNode.js +46 -1
  7. package/dist/src/core/CoreTextNode.js.map +1 -1
  8. package/dist/src/core/CoreTextureManager.d.ts +3 -1
  9. package/dist/src/core/CoreTextureManager.js +4 -1
  10. package/dist/src/core/CoreTextureManager.js.map +1 -1
  11. package/dist/src/core/Stage.d.ts +6 -0
  12. package/dist/src/core/Stage.js +13 -4
  13. package/dist/src/core/Stage.js.map +1 -1
  14. package/dist/src/core/animations/CoreAnimation.d.ts +1 -0
  15. package/dist/src/core/animations/CoreAnimation.js +7 -0
  16. package/dist/src/core/animations/CoreAnimation.js.map +1 -1
  17. package/dist/src/core/lib/ImageWorker.d.ts +16 -0
  18. package/dist/src/core/lib/ImageWorker.js +111 -0
  19. package/dist/src/core/lib/ImageWorker.js.map +1 -0
  20. package/dist/src/core/lib/WebGlContextWrapper.d.ts +4 -0
  21. package/dist/src/core/lib/WebGlContextWrapper.js +7 -2
  22. package/dist/src/core/lib/WebGlContextWrapper.js.map +1 -1
  23. package/dist/src/core/lib/utils.d.ts +9 -0
  24. package/dist/src/core/lib/utils.js +48 -1
  25. package/dist/src/core/lib/utils.js.map +1 -1
  26. package/dist/src/core/renderers/CoreRenderer.d.ts +2 -2
  27. package/dist/src/core/renderers/webgl/WebGlCoreCtxSubTexture.d.ts +2 -1
  28. package/dist/src/core/renderers/webgl/WebGlCoreCtxSubTexture.js +2 -2
  29. package/dist/src/core/renderers/webgl/WebGlCoreCtxSubTexture.js.map +1 -1
  30. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.d.ts +3 -2
  31. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js +23 -21
  32. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js.map +1 -1
  33. package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.d.ts +5 -4
  34. package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.js +10 -14
  35. package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.js.map +1 -1
  36. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.d.ts +4 -1
  37. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js +30 -24
  38. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js.map +1 -1
  39. package/dist/src/core/renderers/webgl/WebGlCoreShader.d.ts +2 -1
  40. package/dist/src/core/renderers/webgl/WebGlCoreShader.js +24 -24
  41. package/dist/src/core/renderers/webgl/WebGlCoreShader.js.map +1 -1
  42. package/dist/src/core/renderers/webgl/internal/RendererUtils.d.ts +8 -5
  43. package/dist/src/core/renderers/webgl/internal/RendererUtils.js +11 -13
  44. package/dist/src/core/renderers/webgl/internal/RendererUtils.js.map +1 -1
  45. package/dist/src/core/renderers/webgl/internal/ShaderUtils.d.ts +3 -2
  46. package/dist/src/core/renderers/webgl/internal/ShaderUtils.js +15 -15
  47. package/dist/src/core/renderers/webgl/internal/ShaderUtils.js.map +1 -1
  48. package/dist/src/core/renderers/webgl/shaders/DefaultShader.js +3 -6
  49. package/dist/src/core/renderers/webgl/shaders/DefaultShader.js.map +1 -1
  50. package/dist/src/core/renderers/webgl/shaders/DefaultShaderBatched.js +3 -3
  51. package/dist/src/core/renderers/webgl/shaders/DefaultShaderBatched.js.map +1 -1
  52. package/dist/src/core/renderers/webgl/shaders/DynamicShader.d.ts +1 -0
  53. package/dist/src/core/renderers/webgl/shaders/DynamicShader.js +32 -12
  54. package/dist/src/core/renderers/webgl/shaders/DynamicShader.js.map +1 -1
  55. package/dist/src/core/renderers/webgl/shaders/RoundedRectangle.js +3 -3
  56. package/dist/src/core/renderers/webgl/shaders/RoundedRectangle.js.map +1 -1
  57. package/dist/src/core/renderers/webgl/shaders/SdfShader.js +3 -3
  58. package/dist/src/core/renderers/webgl/shaders/SdfShader.js.map +1 -1
  59. package/dist/src/core/renderers/webgl/shaders/effects/BorderEffect.js +1 -1
  60. package/dist/src/core/renderers/webgl/shaders/effects/GrayscaleEffect.d.ts +14 -1
  61. package/dist/src/core/renderers/webgl/shaders/effects/GrayscaleEffect.js +15 -5
  62. package/dist/src/core/renderers/webgl/shaders/effects/GrayscaleEffect.js.map +1 -1
  63. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.js +3 -3
  64. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.js.map +1 -1
  65. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.d.ts +2 -1
  66. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.js +4 -2
  67. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.js.map +1 -1
  68. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.d.ts +2 -2
  69. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js +25 -0
  70. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js.map +1 -1
  71. package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.d.ts +1 -1
  72. package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.js +6 -6
  73. package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.js.map +1 -1
  74. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.d.ts +8 -11
  75. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js +140 -81
  76. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js.map +1 -1
  77. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/findNearestMultiple.d.ts +8 -0
  78. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/findNearestMultiple.js +29 -0
  79. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/findNearestMultiple.js.map +1 -0
  80. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.d.ts +4 -3
  81. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.js +15 -11
  82. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.js.map +1 -1
  83. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.d.ts +3 -2
  84. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.js +30 -26
  85. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.js.map +1 -1
  86. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/SdfBufferHelper.d.ts +19 -0
  87. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/SdfBufferHelper.js +84 -0
  88. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/SdfBufferHelper.js.map +1 -0
  89. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutLine.d.ts +8 -0
  90. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutLine.js +40 -0
  91. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutLine.js.map +1 -0
  92. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutText2.d.ts +2 -0
  93. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutText2.js +41 -0
  94. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutText2.js.map +1 -0
  95. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/utils.d.ts +1 -0
  96. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/utils.js +4 -0
  97. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/utils.js.map +1 -0
  98. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2.d.ts +1 -0
  99. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2.js +2 -0
  100. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2.js.map +1 -0
  101. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/roundUpToMultiple.d.ts +9 -0
  102. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/roundUpToMultiple.js +32 -0
  103. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/roundUpToMultiple.js.map +1 -0
  104. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.d.ts +26 -0
  105. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.js +70 -0
  106. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.js.map +1 -0
  107. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/util.d.ts +16 -0
  108. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/util.js +39 -0
  109. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/util.js.map +1 -0
  110. package/dist/src/core/text-rendering/renderers/TextRenderer.d.ts +52 -2
  111. package/dist/src/core/text-rendering/renderers/TextRenderer.js +19 -0
  112. package/dist/src/core/text-rendering/renderers/TextRenderer.js.map +1 -1
  113. package/dist/src/core/textures/ImageTexture.js +14 -9
  114. package/dist/src/core/textures/ImageTexture.js.map +1 -1
  115. package/dist/src/core/utils.d.ts +1 -6
  116. package/dist/src/core/utils.js +3 -2
  117. package/dist/src/core/utils.js.map +1 -1
  118. package/dist/src/main-api/ICoreDriver.d.ts +2 -1
  119. package/dist/src/main-api/RendererMain.d.ts +25 -0
  120. package/dist/src/main-api/RendererMain.js +14 -5
  121. package/dist/src/main-api/RendererMain.js.map +1 -1
  122. package/dist/src/render-drivers/main/MainCoreDriver.d.ts +2 -1
  123. package/dist/src/render-drivers/main/MainCoreDriver.js +6 -4
  124. package/dist/src/render-drivers/main/MainCoreDriver.js.map +1 -1
  125. package/dist/src/render-drivers/main/MainOnlyTextNode.d.ts +10 -0
  126. package/dist/src/render-drivers/main/MainOnlyTextNode.js +45 -0
  127. package/dist/src/render-drivers/main/MainOnlyTextNode.js.map +1 -1
  128. package/dist/src/render-drivers/threadx/TextNodeStruct.d.ts +10 -0
  129. package/dist/src/render-drivers/threadx/TextNodeStruct.js +45 -0
  130. package/dist/src/render-drivers/threadx/TextNodeStruct.js.map +1 -1
  131. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.d.ts +2 -1
  132. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.js +8 -1
  133. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.js.map +1 -1
  134. package/dist/src/render-drivers/threadx/ThreadXMainTextNode.d.ts +5 -0
  135. package/dist/src/render-drivers/threadx/ThreadXMainTextNode.js +5 -0
  136. package/dist/src/render-drivers/threadx/ThreadXMainTextNode.js.map +1 -1
  137. package/dist/src/render-drivers/threadx/ThreadXRendererMessage.d.ts +4 -1
  138. package/dist/src/render-drivers/threadx/ThreadXRendererMessage.js.map +1 -1
  139. package/dist/src/render-drivers/threadx/worker/ThreadXRendererTextNode.d.ts +5 -0
  140. package/dist/src/render-drivers/threadx/worker/ThreadXRendererTextNode.js +10 -0
  141. package/dist/src/render-drivers/threadx/worker/ThreadXRendererTextNode.js.map +1 -1
  142. package/dist/src/render-drivers/threadx/worker/renderer.js +5 -3
  143. package/dist/src/render-drivers/threadx/worker/renderer.js.map +1 -1
  144. package/dist/src/utils.d.ts +2 -1
  145. package/dist/src/utils.js +22 -3
  146. package/dist/src/utils.js.map +1 -1
  147. package/dist/tsconfig.dist.tsbuildinfo +1 -1
  148. package/package.json +3 -2
  149. package/src/common/CommonTypes.ts +9 -0
  150. package/src/core/CoreNode.ts +96 -62
  151. package/src/core/CoreTextNode.ts +58 -2
  152. package/src/core/CoreTextureManager.ts +4 -2
  153. package/src/core/Stage.ts +33 -4
  154. package/src/core/animations/CoreAnimation.ts +8 -0
  155. package/src/core/lib/ContextSpy.ts +41 -0
  156. package/src/core/lib/ImageWorker.ts +124 -0
  157. package/src/core/lib/WebGlContextWrapper.ts +965 -0
  158. package/src/core/lib/utils.ts +68 -1
  159. package/src/core/renderers/CoreRenderer.ts +2 -2
  160. package/src/core/renderers/webgl/WebGlCoreCtxSubTexture.ts +3 -2
  161. package/src/core/renderers/webgl/WebGlCoreCtxTexture.ts +29 -28
  162. package/src/core/renderers/webgl/WebGlCoreRenderOp.ts +13 -17
  163. package/src/core/renderers/webgl/WebGlCoreRenderer.ts +33 -25
  164. package/src/core/renderers/webgl/WebGlCoreShader.ts +34 -25
  165. package/src/core/renderers/webgl/internal/RendererUtils.ts +13 -16
  166. package/src/core/renderers/webgl/internal/ShaderUtils.ts +16 -15
  167. package/src/core/renderers/webgl/shaders/DefaultShader.ts +3 -7
  168. package/src/core/renderers/webgl/shaders/DefaultShaderBatched.ts +3 -3
  169. package/src/core/renderers/webgl/shaders/DynamicShader.ts +42 -14
  170. package/src/core/renderers/webgl/shaders/RoundedRectangle.ts +3 -3
  171. package/src/core/renderers/webgl/shaders/SdfShader.ts +3 -3
  172. package/src/core/renderers/webgl/shaders/effects/BorderEffect.ts +1 -1
  173. package/src/core/renderers/webgl/shaders/effects/GrayscaleEffect.ts +35 -5
  174. package/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.ts +3 -3
  175. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.test.ts +9 -3
  176. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.ts +4 -2
  177. package/src/core/text-rendering/renderers/CanvasTextRenderer.ts +27 -1
  178. package/src/core/text-rendering/renderers/LightningTextTextureRenderer.ts +7 -7
  179. package/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.ts +193 -103
  180. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.ts +26 -18
  181. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.ts +40 -28
  182. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/measureText.test.ts +6 -1
  183. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.test.ts +205 -0
  184. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/{makeRenderWindow.ts → setRenderWindow.ts} +50 -21
  185. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/util.ts +40 -0
  186. package/src/core/text-rendering/renderers/TextRenderer.ts +75 -2
  187. package/src/core/textures/ImageTexture.ts +17 -9
  188. package/src/core/utils.ts +87 -85
  189. package/src/env.d.ts +7 -0
  190. package/src/main-api/ICoreDriver.ts +2 -1
  191. package/src/main-api/RendererMain.ts +43 -5
  192. package/src/render-drivers/main/MainCoreDriver.ts +8 -5
  193. package/src/render-drivers/main/MainOnlyTextNode.ts +55 -1
  194. package/src/render-drivers/threadx/TextNodeStruct.ts +45 -0
  195. package/src/render-drivers/threadx/ThreadXCoreDriver.ts +10 -2
  196. package/src/render-drivers/threadx/ThreadXMainTextNode.ts +10 -0
  197. package/src/render-drivers/threadx/ThreadXRendererMessage.ts +5 -1
  198. package/src/render-drivers/threadx/worker/ThreadXRendererTextNode.ts +15 -0
  199. package/src/render-drivers/threadx/worker/renderer.ts +6 -4
  200. package/src/utils.ts +25 -4
  201. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/makeRenderWindow.test.ts +0 -136
@@ -18,11 +18,15 @@
18
18
  */
19
19
 
20
20
  import {
21
- intersectBound,
22
21
  type Bound,
23
22
  type Rect,
24
23
  createBound,
25
24
  type BoundWithValid,
25
+ intersectRect,
26
+ type RectWithValid,
27
+ copyRect,
28
+ boundsOverlap,
29
+ convertBoundToRect,
26
30
  } from '../../../lib/utils.js';
27
31
  import {
28
32
  TextRenderer,
@@ -35,7 +39,10 @@ import { SdfTrFontFace } from '../../font-face-types/SdfTrFontFace/SdfTrFontFace
35
39
  import { FLOATS_PER_GLYPH } from './internal/constants.js';
36
40
  import { getStartConditions } from './internal/getStartConditions.js';
37
41
  import { layoutText } from './internal/layoutText.js';
38
- import { makeRenderWindow } from './internal/makeRenderWindow.js';
42
+ import {
43
+ setRenderWindow,
44
+ type SdfRenderWindow,
45
+ } from './internal/setRenderWindow.js';
39
46
  import type { TrFontFace } from '../../font-face-types/TrFontFace.js';
40
47
  import { TrFontManager, type FontFamilyMap } from '../../TrFontManager.js';
41
48
  import { assertTruthy, mergeColorAlpha } from '../../../../utils.js';
@@ -77,9 +84,11 @@ export interface SdfTextRendererState extends TextRendererState {
77
84
  */
78
85
  lineCache: LineCacheItem[];
79
86
 
80
- renderWindow: Bound | undefined;
87
+ renderWindow: SdfRenderWindow;
88
+
89
+ elementBounds: BoundWithValid;
81
90
 
82
- visibleWindow: BoundWithValid;
91
+ clippingRect: RectWithValid;
83
92
 
84
93
  bufferNumFloats: number;
85
94
 
@@ -99,13 +108,14 @@ export interface SdfTextRendererState extends TextRendererState {
99
108
  }
100
109
 
101
110
  /**
102
- * Ephemeral bounds object used for intersection calculations
103
- *
104
- * @remarks
105
- * Used to avoid creating a new object every time we need to intersect
106
- * element bounds.
111
+ * Ephemeral rect object used for calculations
107
112
  */
108
- const tmpElementBounds = createBound(0, 0, 0, 0);
113
+ const tmpRect: Rect = {
114
+ x: 0,
115
+ y: 0,
116
+ width: 0,
117
+ height: 0,
118
+ };
109
119
 
110
120
  /**
111
121
  * Singleton class for rendering text using signed distance fields.
@@ -173,11 +183,31 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
173
183
  },
174
184
  x: (state, value) => {
175
185
  state.props.x = value;
176
- this.invalidateVisibleWindowCache(state);
186
+ if (state.elementBounds.valid) {
187
+ this.setElementBoundsX(state);
188
+ // Only schedule an update if the text is not already rendered
189
+ // (renderWindow is invalid) and the element possibly overlaps the screen
190
+ // This is to avoid unnecessary updates when we know text is off-screen
191
+ if (
192
+ !state.renderWindow.valid &&
193
+ boundsOverlap(state.elementBounds, this.rendererBounds)
194
+ ) {
195
+ this.scheduleUpdateState(state);
196
+ }
197
+ }
177
198
  },
178
199
  y: (state, value) => {
179
200
  state.props.y = value;
180
- this.invalidateVisibleWindowCache(state);
201
+ if (state.elementBounds.valid) {
202
+ this.setElementBoundsY(state);
203
+ // See x() for explanation
204
+ if (
205
+ !state.renderWindow.valid &&
206
+ boundsOverlap(state.elementBounds, this.rendererBounds)
207
+ ) {
208
+ this.scheduleUpdateState(state);
209
+ }
210
+ }
181
211
  },
182
212
  contain: (state, value) => {
183
213
  state.props.contain = value;
@@ -209,6 +239,26 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
209
239
  state.props.letterSpacing = value;
210
240
  this.invalidateLayoutCache(state);
211
241
  },
242
+ lineHeight: (state, value) => {
243
+ state.props.lineHeight = value;
244
+ this.invalidateLayoutCache(state);
245
+ },
246
+ maxLines: (state, value) => {
247
+ state.props.maxLines = value;
248
+ this.invalidateLayoutCache(state);
249
+ },
250
+ textBaseline: (state, value) => {
251
+ state.props.textBaseline = value;
252
+ this.invalidateLayoutCache(state);
253
+ },
254
+ verticalAlign: (state, value) => {
255
+ state.props.verticalAlign = value;
256
+ this.invalidateLayoutCache(state);
257
+ },
258
+ overflowSuffix: (state, value) => {
259
+ state.props.overflowSuffix = value;
260
+ this.invalidateLayoutCache(state);
261
+ },
212
262
  debug: (state, value) => {
213
263
  state.props.debug = value;
214
264
  },
@@ -262,14 +312,37 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
262
312
  emitter: new EventEmitter(),
263
313
  lineCache: [],
264
314
  forceFullLayoutCalc: false,
265
- renderWindow: undefined,
266
- visibleWindow: {
315
+ renderWindow: {
316
+ screen: {
317
+ x1: 0,
318
+ y1: 0,
319
+ x2: 0,
320
+ y2: 0,
321
+ },
322
+ sdf: {
323
+ x1: 0,
324
+ y1: 0,
325
+ x2: 0,
326
+ y2: 0,
327
+ },
328
+ firstLineIdx: 0,
329
+ numLines: 0,
330
+ valid: false,
331
+ },
332
+ elementBounds: {
267
333
  x1: 0,
268
334
  y1: 0,
269
335
  x2: 0,
270
336
  y2: 0,
271
337
  valid: false,
272
338
  },
339
+ clippingRect: {
340
+ x: 0,
341
+ y: 0,
342
+ width: 0,
343
+ height: 0,
344
+ valid: false,
345
+ },
273
346
  bufferNumFloats: 0,
274
347
  bufferNumQuads: 0,
275
348
  vertexBuffer: undefined,
@@ -325,22 +398,39 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
325
398
  // If the font is loaded then so should the data
326
399
  assertTruthy(trFontFace.data, 'Font face data should be loaded');
327
400
 
328
- const { text, fontSize, x, y, contain, width, height, scrollable } =
329
- state.props;
401
+ const {
402
+ text,
403
+ fontSize,
404
+ x,
405
+ y,
406
+ contain,
407
+ width,
408
+ height,
409
+ lineHeight,
410
+ verticalAlign,
411
+ scrollable,
412
+ overflowSuffix,
413
+ maxLines,
414
+ } = state.props;
330
415
 
331
416
  // scrollY only has an effect when contain === 'both' and scrollable === true
332
417
  const scrollY = contain === 'both' && scrollable ? state.props.scrollY : 0;
333
418
 
334
- let { renderWindow } = state;
419
+ const { renderWindow } = state;
335
420
 
336
- // Needed in renderWindow calculation
337
- const sdfLineHeight = trFontFace.data.info.size;
421
+ /**
422
+ * The font size of the SDF font face (the basis for SDF space units)
423
+ */
424
+ const sdfFontSize = trFontFace.data.info.size;
338
425
 
339
426
  /**
340
- * Divide screen space points by this to get the SDF space points
341
- * Mulitple SDF space points by this to get screen space points
427
+ * Divide screen space units by this to get the SDF space units
428
+ * Mulitple SDF space units by this to get screen space units
342
429
  */
343
- const fontSizeRatio = fontSize / sdfLineHeight;
430
+ const fontSizeRatio = fontSize / sdfFontSize;
431
+
432
+ // Needed in renderWindow calculation
433
+ const sdfLineHeight = lineHeight / fontSizeRatio;
344
434
 
345
435
  state.distanceRange =
346
436
  fontSizeRatio * trFontFace.data.distanceField.distanceRange;
@@ -352,65 +442,66 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
352
442
  vertexBuffer = new Float32Array(neededLength * 2);
353
443
  }
354
444
 
355
- const visibleWindow = state.visibleWindow;
356
- // If the visibleWindow is not valid, calculate it
357
- if (!visibleWindow.valid) {
358
- // Figure out whats actually in the bounds of the renderer/canvas (visibleWindow)
359
- const elementBounds = createBound(
360
- x,
361
- y,
362
- contain !== 'none' ? x + width : Infinity,
363
- contain === 'both' ? y + height : Infinity,
364
- tmpElementBounds, // Prevent allocation by using this temp object
365
- );
366
- /**
367
- * Area that is visible on the screen.
368
- */
369
- intersectBound(this.rendererBounds, elementBounds, state.visibleWindow);
370
- visibleWindow.valid = true;
445
+ const elementBounds = state.elementBounds;
446
+ if (!elementBounds.valid) {
447
+ this.setElementBoundsX(state);
448
+ this.setElementBoundsY(state);
449
+ elementBounds.valid = true;
371
450
  }
372
451
 
373
452
  // Return early if we're still viewing inside the established render window
374
453
  // No need to re-render what we've already rendered
375
454
  // (Only if there's an established renderWindow and we're not suppressing early exit)
376
- if (!forceFullLayoutCalc && renderWindow) {
455
+ if (!forceFullLayoutCalc && renderWindow.valid) {
456
+ const rwScreen = renderWindow.screen;
377
457
  if (
378
- x + renderWindow.x1 <= visibleWindow.x1 &&
379
- x + renderWindow.x2 >= visibleWindow.x2 &&
380
- y - scrollY + renderWindow.y1 <= visibleWindow.y1 &&
381
- y - scrollY + renderWindow.y2 >= visibleWindow.y2
458
+ x + rwScreen.x1 <= elementBounds.x1 &&
459
+ x + rwScreen.x2 >= elementBounds.x2 &&
460
+ y - scrollY + rwScreen.y1 <= elementBounds.y1 &&
461
+ y - scrollY + rwScreen.y2 >= elementBounds.y2
382
462
  ) {
383
463
  this.setStatus(state, 'loaded');
384
464
  return;
385
465
  }
386
- // Otherwise clear the renderWindow so it can be redone
387
- renderWindow = state.renderWindow = undefined;
466
+ // Otherwise invalidate the renderWindow so it can be redone
467
+ renderWindow.valid = false;
388
468
  this.setStatus(state, 'loading');
389
469
  }
390
470
 
391
471
  const { offsetY, textAlign } = state.props;
392
472
 
393
473
  // Create a new renderWindow if needed
394
- if (!renderWindow) {
395
- const visibleWindowHeight = visibleWindow.y2 - visibleWindow.y1;
396
- const maxLinesPerCanvasPage = Math.ceil(
397
- visibleWindowHeight / sdfLineHeight,
474
+ if (!renderWindow.valid) {
475
+ const isPossiblyOnScreen = boundsOverlap(
476
+ elementBounds,
477
+ this.rendererBounds,
398
478
  );
399
- renderWindow = makeRenderWindow(
479
+
480
+ if (!isPossiblyOnScreen) {
481
+ // If the element is not possibly on screen, we can skip the layout and rendering completely
482
+ return;
483
+ }
484
+
485
+ setRenderWindow(
486
+ renderWindow,
400
487
  x,
401
488
  y,
402
489
  scrollY,
403
- sdfLineHeight,
404
- maxLinesPerCanvasPage,
405
- visibleWindow,
490
+ lineHeight,
491
+ contain === 'both' ? elementBounds.y2 - elementBounds.y1 : 0,
492
+ elementBounds,
493
+ fontSizeRatio,
406
494
  );
495
+ // console.log('newRenderWindow', renderWindow);
407
496
  }
408
497
 
409
498
  const start = getStartConditions(
410
- fontSize,
499
+ sdfFontSize,
500
+ sdfLineHeight,
501
+ lineHeight,
502
+ verticalAlign,
411
503
  offsetY,
412
504
  fontSizeRatio,
413
- sdfLineHeight,
414
505
  renderWindow,
415
506
  lineCache,
416
507
  textH,
@@ -427,21 +518,24 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
427
518
 
428
519
  const out2 = layoutText(
429
520
  start.lineIndex,
430
- start.x,
431
- start.y,
521
+ start.sdfX,
522
+ start.sdfY,
432
523
  text,
433
524
  textAlign,
434
525
  width,
435
526
  height,
436
527
  fontSize,
528
+ lineHeight,
437
529
  letterSpacing,
438
530
  vertexBuffer,
439
531
  contain,
440
532
  lineCache,
441
- renderWindow,
533
+ renderWindow.sdf,
442
534
  trFontFace,
443
535
  forceFullLayoutCalc,
444
536
  scrollable,
537
+ overflowSuffix,
538
+ maxLines,
445
539
  );
446
540
 
447
541
  state.bufferUploaded = false;
@@ -468,7 +562,7 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
468
562
  override renderQuads(
469
563
  state: SdfTextRendererState,
470
564
  transform: Matrix3d,
471
- clippingRect: Rect | null,
565
+ clippingRect: Readonly<RectWithValid>,
472
566
  alpha: number,
473
567
  ): void {
474
568
  if (!state.vertexBuffer) {
@@ -476,14 +570,8 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
476
570
  return;
477
571
  }
478
572
 
479
- const drawStartTime = performance.now();
480
-
481
- const { sdfShader } = this;
482
-
483
573
  const { renderer } = this.stage;
484
574
 
485
- const { appWidth, appHeight } = this.stage.options;
486
-
487
575
  const { fontSize, color, contain, scrollable, zIndex, debug } = state.props;
488
576
 
489
577
  // scrollY only has an effect when contain === 'both' and scrollable === true
@@ -496,14 +584,15 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
496
584
  vertexBuffer,
497
585
  bufferUploaded,
498
586
  trFontFace,
587
+ elementBounds,
499
588
  } = state;
500
589
 
501
590
  let { webGlBuffers } = state;
502
591
 
503
592
  if (!webGlBuffers) {
504
- const gl = renderer.gl;
593
+ const glw = renderer.glw;
505
594
  const stride = 4 * Float32Array.BYTES_PER_ELEMENT;
506
- const webGlBuffer = gl.createBuffer();
595
+ const webGlBuffer = glw.createBuffer();
507
596
  assertTruthy(webGlBuffer);
508
597
  state.webGlBuffers = new BufferCollection([
509
598
  {
@@ -512,7 +601,7 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
512
601
  a_position: {
513
602
  name: 'a_position',
514
603
  size: 2, // 2 components per iteration
515
- type: gl.FLOAT, // the data is 32bit floats
604
+ type: glw.FLOAT, // the data is 32bit floats
516
605
  normalized: false, // don't normalize the data
517
606
  stride, // 0 = move forward size * sizeof(type) each iteration to get the next position
518
607
  offset: 0, // start at the beginning of the buffer
@@ -520,7 +609,7 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
520
609
  a_textureCoordinate: {
521
610
  name: 'a_textureCoordinate',
522
611
  size: 2,
523
- type: gl.FLOAT,
612
+ type: glw.FLOAT,
524
613
  normalized: false,
525
614
  stride,
526
615
  offset: 2 * Float32Array.BYTES_PER_ELEMENT,
@@ -534,18 +623,33 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
534
623
  }
535
624
 
536
625
  if (!bufferUploaded) {
537
- const gl = renderer.gl;
626
+ const glw = renderer.glw;
538
627
 
539
628
  const buffer = webGlBuffers?.getBuffer('a_textureCoordinate') ?? null;
540
- gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
541
- gl.bufferData(gl.ARRAY_BUFFER, vertexBuffer, gl.STATIC_DRAW);
629
+ glw.arrayBufferData(buffer, vertexBuffer, glw.STATIC_DRAW);
542
630
  state.bufferUploaded = true;
543
631
  }
544
632
 
545
633
  assertTruthy(trFontFace);
634
+ if (scrollable && contain === 'both') {
635
+ assertTruthy(elementBounds.valid);
636
+ const elementRect = convertBoundToRect(elementBounds, tmpRect);
637
+
638
+ if (clippingRect.valid) {
639
+ state.clippingRect.valid = true;
640
+ clippingRect = intersectRect(
641
+ clippingRect,
642
+ elementRect,
643
+ state.clippingRect,
644
+ );
645
+ } else {
646
+ state.clippingRect.valid = true;
647
+ clippingRect = copyRect(elementRect, state.clippingRect);
648
+ }
649
+ }
546
650
 
547
651
  const renderOp = new WebGlCoreRenderOp(
548
- renderer.gl,
652
+ renderer.glw,
549
653
  renderer.options,
550
654
  webGlBuffers,
551
655
  this.sdfShader,
@@ -577,23 +681,6 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
577
681
 
578
682
  renderer.addRenderOp(renderOp);
579
683
 
580
- // const elementRect = {
581
- // x: x,
582
- // y: y,
583
- // w: contain !== 'none' ? width : textW,
584
- // h: contain === 'both' ? height : textH,
585
- // };
586
-
587
- // const visibleRect = intersectRect(
588
- // {
589
- // x: 0,
590
- // y: 0,
591
- // w: renderer.w,
592
- // h: renderer.h,
593
- // },
594
- // elementRect,
595
- // );
596
-
597
684
  // if (!debug.disableScissor) {
598
685
  // renderer.enableScissor(
599
686
  // visibleRect.x,
@@ -655,17 +742,6 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
655
742
  ) as SdfTrFontFace | undefined;
656
743
  }
657
744
 
658
- /**
659
- * Invalidate the visible window stored in the state. This will cause a new
660
- * visible window to be calculated on the next update.
661
- *
662
- * @param state
663
- */
664
- protected invalidateVisibleWindowCache(state: SdfTextRendererState): void {
665
- state.visibleWindow.valid = false;
666
- this.scheduleUpdateState(state);
667
- }
668
-
669
745
  /**
670
746
  * Invalidate the layout cache stored in the state. This will cause the text
671
747
  * to be re-layed out on the next update.
@@ -676,12 +752,26 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
676
752
  * @param state
677
753
  */
678
754
  protected invalidateLayoutCache(state: SdfTextRendererState): void {
679
- state.visibleWindow.valid = false;
680
- state.renderWindow = undefined;
755
+ state.renderWindow.valid = false;
756
+ state.elementBounds.valid = false;
681
757
  state.textH = undefined;
682
758
  state.textW = undefined;
683
759
  state.lineCache = [];
684
760
  this.setStatus(state, 'loading');
685
761
  this.scheduleUpdateState(state);
686
762
  }
763
+
764
+ protected setElementBoundsX(state: SdfTextRendererState): void {
765
+ const { x, contain, width } = state.props;
766
+ const { elementBounds } = state;
767
+ elementBounds.x1 = x;
768
+ elementBounds.x2 = contain !== 'none' ? x + width : Infinity;
769
+ }
770
+
771
+ protected setElementBoundsY(state: SdfTextRendererState): void {
772
+ const { y, contain, height } = state.props;
773
+ const { elementBounds } = state;
774
+ elementBounds.y1 = y;
775
+ elementBounds.y2 = contain === 'both' ? y + height : Infinity;
776
+ }
687
777
  }
@@ -17,8 +17,10 @@
17
17
  * limitations under the License.
18
18
  */
19
19
 
20
+ import type { Bound } from '../../../../lib/utils.js';
20
21
  import type { TrProps, TextRendererState } from '../../TextRenderer.js';
21
22
  import type { SdfTextRendererState } from '../SdfTextRenderer.js';
23
+ import type { SdfRenderWindow } from './setRenderWindow.js';
22
24
 
23
25
  /**
24
26
  * Gets the start conditions for the layout loop.
@@ -35,42 +37,48 @@ import type { SdfTextRendererState } from '../SdfTextRenderer.js';
35
37
  * @returns
36
38
  */
37
39
  export function getStartConditions(
38
- fontSize: TrProps['fontSize'],
40
+ sdfFontSize: number,
41
+ sdfLineHeight: number,
42
+ lineHeight: number,
43
+ verticalAlign: TrProps['verticalAlign'],
39
44
  offsetY: TrProps['offsetY'],
40
45
  fontSizeRatio: number,
41
- sdfLineHeight: number,
42
- renderWindow: SdfTextRendererState['renderWindow'],
46
+ renderWindow: SdfRenderWindow,
43
47
  lineCache: SdfTextRendererState['lineCache'],
44
48
  textH: TextRendererState['textH'],
45
49
  ):
46
50
  | {
47
- x: number;
48
- y: number;
51
+ sdfX: number;
52
+ sdfY: number;
49
53
  lineIndex: number;
50
54
  }
51
55
  | undefined {
52
56
  // State variables
53
- let startLineIndex = 0;
54
- if (renderWindow) {
55
- startLineIndex = Math.min(
56
- Math.max(Math.floor(renderWindow.y1 / fontSize), 0),
57
- lineCache.length,
58
- );
59
- }
57
+ const startLineIndex = Math.min(
58
+ Math.max(renderWindow.firstLineIdx, 0),
59
+ lineCache.length,
60
+ );
60
61
 
61
- // TODO: Possibly break out startX / startY into a separate function
62
62
  // TODO: (fontSize / 6.4286 / fontSizeRatio) Adding this to the startY helps the text line up better with Canvas rendered text
63
- const startX = 0;
64
- const startY = offsetY / fontSizeRatio + startLineIndex * sdfLineHeight; // TODO: Figure out what determines the initial y offset of text.
63
+ const sdfStartX = 0;
64
+ let sdfVerticalAlignYOffset = 0;
65
+ if (verticalAlign === 'middle') {
66
+ sdfVerticalAlignYOffset = (sdfLineHeight - sdfFontSize) / 2;
67
+ } else if (verticalAlign === 'bottom') {
68
+ sdfVerticalAlignYOffset = sdfLineHeight - sdfFontSize;
69
+ }
70
+ const sdfOffsetY = offsetY / fontSizeRatio;
71
+ const sdfStartY =
72
+ sdfOffsetY + startLineIndex * sdfLineHeight + sdfVerticalAlignYOffset; // TODO: Figure out what determines the initial y offset of text.
65
73
 
66
74
  // Don't attempt to render anything if we know we're starting past the established end of the text
67
- if (textH && startY >= textH / fontSizeRatio) {
75
+ if (textH && sdfStartY >= textH / fontSizeRatio) {
68
76
  return;
69
77
  }
70
78
 
71
79
  return {
72
- x: startX,
73
- y: startY,
80
+ sdfX: sdfStartX,
81
+ sdfY: sdfStartY,
74
82
  lineIndex: startLineIndex,
75
83
  };
76
84
  }