@tangram.gl/tangram-renderer 0.0.0-stage → 0.0.0

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 (321) hide show
  1. package/README.md +59 -2
  2. package/dist/core.js +36923 -0
  3. package/dist/core.js.map +6 -0
  4. package/dist/index.js +32 -0
  5. package/dist/loaders-gl-worker.js +82 -0
  6. package/dist/loaders-gl-worker.js.map +6 -0
  7. package/dist/map-logic.js +2 -0
  8. package/dist/map-logic.js.map +6 -0
  9. package/dist/projected-basemaps-worker.js +3 -0
  10. package/dist/projected-basemaps-worker.js.map +6 -0
  11. package/dist/shader-modules.js +141 -0
  12. package/dist/shader-modules.js.map +6 -0
  13. package/dist/style-schema.js +126 -0
  14. package/dist/style-schema.js.map +6 -0
  15. package/dist/tangram-style.schema.json +882 -0
  16. package/dist/tangram.debug.mjs +37139 -0
  17. package/dist/tangram.debug.mjs.map +6 -0
  18. package/dist/tangram.min.mjs +4950 -0
  19. package/dist/types/builders/earcut.d.ts +15 -0
  20. package/dist/types/core.d.ts +29 -0
  21. package/dist/types/gl/constants.d.ts +2 -0
  22. package/dist/types/gl/globe_mesh.d.ts +48 -0
  23. package/dist/types/gl/glsl.d.ts +17 -0
  24. package/dist/types/gl/vertex-constants.d.ts +4 -0
  25. package/dist/types/gl/vertex-types.d.ts +34 -0
  26. package/dist/types/gl/vertex_data.d.ts +32 -0
  27. package/dist/types/gl/vertex_elements.d.ts +8 -0
  28. package/dist/types/gl/vertex_layout.d.ts +32 -0
  29. package/dist/types/glsl.d.ts +14 -0
  30. package/dist/types/gpu/luma_device_renderer.d.ts +66 -0
  31. package/dist/types/gpu/resource_lifecycle.d.ts +4 -0
  32. package/dist/types/gpu/tangram_gpu_backend.d.ts +151 -0
  33. package/dist/types/index.d.ts +155 -0
  34. package/dist/types/lights/light-definitions.d.ts +121 -0
  35. package/dist/types/map-logic/draped-terrain-bounds.d.ts +41 -0
  36. package/dist/types/map-logic/globe-terrain-preparation.d.ts +85 -0
  37. package/dist/types/map-logic/globe-terrain.d.ts +54 -0
  38. package/dist/types/map-logic/index.d.ts +33 -0
  39. package/dist/types/map-logic/label-identity.d.ts +22 -0
  40. package/dist/types/map-logic/label-placement.d.ts +32 -0
  41. package/dist/types/map-logic/screen-bounds.d.ts +15 -0
  42. package/dist/types/map-logic/terrain-data.d.ts +55 -0
  43. package/dist/types/map-logic/terrain-error.d.ts +51 -0
  44. package/dist/types/map-logic/terrain-ground-topology.d.ts +26 -0
  45. package/dist/types/map-logic/terrain-height-field.d.ts +59 -0
  46. package/dist/types/map-logic/terrain-navigation.d.ts +27 -0
  47. package/dist/types/map-logic/terrain-neighborhood.d.ts +5 -0
  48. package/dist/types/map-logic/terrain-query.d.ts +33 -0
  49. package/dist/types/map-logic/terrain-resource-budget.d.ts +51 -0
  50. package/dist/types/map-logic/terrain-transition-topology.d.ts +23 -0
  51. package/dist/types/map-logic/tile-build-queue.d.ts +51 -0
  52. package/dist/types/map-logic/tile-cache-policy.d.ts +46 -0
  53. package/dist/types/map-logic/tile-residency.d.ts +17 -0
  54. package/dist/types/map-logic/triangle-query-index.d.ts +87 -0
  55. package/dist/types/procedures/js-yaml.d.ts +15 -0
  56. package/dist/types/procedures/mesh-projector.d.ts +107 -0
  57. package/dist/types/procedures/mvt-dependencies.d.ts +20 -0
  58. package/dist/types/procedures/projected-coordinate-transform.d.ts +27 -0
  59. package/dist/types/procedures/projection-batch-executor.d.ts +53 -0
  60. package/dist/types/procedures/scene-yaml-legacy.d.ts +6 -0
  61. package/dist/types/procedures/terrain-draping.d.ts +165 -0
  62. package/dist/types/procedures/terrain-globe.d.ts +6 -0
  63. package/dist/types/procedures/terrain-styled-topology.d.ts +34 -0
  64. package/dist/types/procedures/web-mercator-legacy.d.ts +4 -0
  65. package/dist/types/procedures/web-mercator-math.d.ts +4 -0
  66. package/dist/types/scene/globals.d.ts +11 -0
  67. package/dist/types/scene/ground_footprint.d.ts +16 -0
  68. package/dist/types/scene/host_frame.d.ts +54 -0
  69. package/dist/types/scene/projection_math.d.ts +52 -0
  70. package/dist/types/scene/scene-resource-types.d.ts +177 -0
  71. package/dist/types/scene/scene_bundle.d.ts +69 -0
  72. package/dist/types/scene/visibility_adapter.d.ts +106 -0
  73. package/dist/types/selection/draped-terrain-surface.d.ts +78 -0
  74. package/dist/types/selection/terrain_surface.d.ts +149 -0
  75. package/dist/types/shader-modules/globe-horizon.d.ts +15 -0
  76. package/dist/types/shader-modules/height-decode.d.ts +13 -0
  77. package/dist/types/shader-modules/hillshade.d.ts +13 -0
  78. package/dist/types/shader-modules/index.d.ts +6 -0
  79. package/dist/types/shader-modules/planar.d.ts +12 -0
  80. package/dist/types/shader-modules/sphere-map.d.ts +13 -0
  81. package/dist/types/shader-modules/triplanar.d.ts +15 -0
  82. package/dist/types/sources/decoded_tile_store.d.ts +95 -0
  83. package/dist/types/sources/tile_source_metadata.d.ts +32 -0
  84. package/dist/types/styles/text/fontfaceobserver.d.ts +10 -0
  85. package/dist/types/tile/tile_id.d.ts +37 -0
  86. package/dist/types/tile/tile_traversal_adapter.d.ts +63 -0
  87. package/dist/types/types.d.ts +293 -0
  88. package/dist/types/utils/geo.d.ts +57 -0
  89. package/dist/types/utils/hash.d.ts +1 -0
  90. package/dist/types/utils/log.d.ts +27 -0
  91. package/dist/types/utils/props.d.ts +6 -0
  92. package/dist/types/utils/subscribe.d.ts +10 -0
  93. package/dist/types/utils/thread.d.ts +6 -0
  94. package/dist/types/utils/urls.d.ts +26 -0
  95. package/dist/types/utils/utils.d.ts +26 -0
  96. package/dist/types/utils/version.d.ts +2 -0
  97. package/dist/types/utils/worker-types.d.ts +68 -0
  98. package/dist/types/utils/worker_broker.d.ts +3 -0
  99. package/package.json +103 -3
  100. package/src/builders/common.ts +41 -0
  101. package/src/builders/earcut.d.ts +15 -0
  102. package/src/builders/geometry-types.ts +60 -0
  103. package/src/builders/points.ts +115 -0
  104. package/src/builders/polygons.ts +225 -0
  105. package/src/builders/polylines.ts +682 -0
  106. package/src/builders/wireframe.ts +31 -0
  107. package/src/core.d.ts +29 -0
  108. package/src/core.ts +33 -0
  109. package/src/experimental/loaders-gl-worker.ts +19 -0
  110. package/src/experimental/projected-basemaps-worker.ts +13 -0
  111. package/src/experimental/projected-mesh-cache.ts +137 -0
  112. package/src/experimental/projected-mesh-domain.ts +110 -0
  113. package/src/experimental/projected-mesh-refinement.ts +193 -0
  114. package/src/experimental/projected-mesh.ts +399 -0
  115. package/src/experimental/projected-normal.ts +26 -0
  116. package/src/experimental/projected-symbol-mesh.ts +74 -0
  117. package/src/gl/constants.ts +18 -0
  118. package/src/gl/context.ts +103 -0
  119. package/src/gl/extensions.ts +30 -0
  120. package/src/gl/globe_mesh.ts +285 -0
  121. package/src/gl/glsl.ts +257 -0
  122. package/src/gl/mesh-types.ts +56 -0
  123. package/src/gl/render_state.ts +111 -0
  124. package/src/gl/shader_program.ts +1310 -0
  125. package/src/gl/texture.ts +814 -0
  126. package/src/gl/uniform_buffer.ts +340 -0
  127. package/src/gl/vao.ts +154 -0
  128. package/src/gl/vbo_mesh.ts +349 -0
  129. package/src/gl/vertex-constants.ts +19 -0
  130. package/src/gl/vertex-types.ts +35 -0
  131. package/src/gl/vertex_data.ts +126 -0
  132. package/src/gl/vertex_elements.ts +54 -0
  133. package/src/gl/vertex_layout.ts +241 -0
  134. package/src/glsl.d.ts +14 -0
  135. package/src/gpu/luma_device_renderer.ts +579 -0
  136. package/src/gpu/pixel_readback.ts +51 -0
  137. package/src/gpu/resource_lifecycle.ts +32 -0
  138. package/src/gpu/tangram_gpu_backend.ts +195 -0
  139. package/src/index.d.ts +155 -0
  140. package/src/index.ts +105 -0
  141. package/src/labels/collision-types.ts +94 -0
  142. package/src/labels/collision.ts +273 -0
  143. package/src/labels/collision_grid.ts +61 -0
  144. package/src/labels/intersect.ts +30 -0
  145. package/src/labels/label-types.ts +91 -0
  146. package/src/labels/label.ts +207 -0
  147. package/src/labels/label_line.ts +801 -0
  148. package/src/labels/label_point.ts +131 -0
  149. package/src/labels/main-pass-types.ts +73 -0
  150. package/src/labels/main_pass.ts +221 -0
  151. package/src/labels/point_anchor.ts +100 -0
  152. package/src/labels/point_placement.ts +150 -0
  153. package/src/labels/projected-pass.ts +259 -0
  154. package/src/labels/repeat_group.ts +72 -0
  155. package/src/lights/ambient_light.glsl +18 -0
  156. package/src/lights/directional_light.glsl +39 -0
  157. package/src/lights/geographic-lights.ts +21 -0
  158. package/src/lights/light-definitions.ts +285 -0
  159. package/src/lights/light.ts +590 -0
  160. package/src/lights/lighting-uniforms.ts +80 -0
  161. package/src/lights/lighting-wgsl.ts +116 -0
  162. package/src/lights/material.glsl +237 -0
  163. package/src/lights/material.ts +145 -0
  164. package/src/lights/native-falloff.ts +37 -0
  165. package/src/lights/point_light.glsl +96 -0
  166. package/src/lights/spot_light.glsl +111 -0
  167. package/src/map-logic/draped-terrain-bounds.ts +71 -0
  168. package/src/map-logic/globe-terrain-preparation.ts +217 -0
  169. package/src/map-logic/globe-terrain.ts +296 -0
  170. package/src/map-logic/index.ts +37 -0
  171. package/src/map-logic/label-identity.ts +36 -0
  172. package/src/map-logic/label-placement.ts +117 -0
  173. package/src/map-logic/screen-bounds.ts +34 -0
  174. package/src/map-logic/terrain-data.ts +107 -0
  175. package/src/map-logic/terrain-error.ts +134 -0
  176. package/src/map-logic/terrain-ground-topology.ts +164 -0
  177. package/src/map-logic/terrain-height-field.ts +254 -0
  178. package/src/map-logic/terrain-navigation.ts +50 -0
  179. package/src/map-logic/terrain-neighborhood.ts +43 -0
  180. package/src/map-logic/terrain-query.ts +51 -0
  181. package/src/map-logic/terrain-resource-budget.ts +124 -0
  182. package/src/map-logic/terrain-transition-topology.ts +164 -0
  183. package/src/map-logic/tile-build-queue.ts +110 -0
  184. package/src/map-logic/tile-cache-policy.ts +89 -0
  185. package/src/map-logic/tile-residency.ts +50 -0
  186. package/src/map-logic/triangle-query-index.ts +265 -0
  187. package/src/procedures/js-yaml.d.ts +15 -0
  188. package/src/procedures/mesh-projector.ts +191 -0
  189. package/src/procedures/mlt-loaders.ts +55 -0
  190. package/src/procedures/mvt-dependencies.d.ts +20 -0
  191. package/src/procedures/mvt-legacy.ts +150 -0
  192. package/src/procedures/mvt-loaders.ts +53 -0
  193. package/src/procedures/mvt-parser.ts +48 -0
  194. package/src/procedures/mvt-properties.ts +36 -0
  195. package/src/procedures/mvt-tile-provider.ts +72 -0
  196. package/src/procedures/pmtiles-loader.ts +75 -0
  197. package/src/procedures/projected-coordinate-transform.ts +79 -0
  198. package/src/procedures/projection-batch-executor.ts +140 -0
  199. package/src/procedures/scene-yaml-legacy.ts +16 -0
  200. package/src/procedures/scene-yaml-loaders.ts +10 -0
  201. package/src/procedures/terrain-draping.ts +713 -0
  202. package/src/procedures/terrain-globe.ts +32 -0
  203. package/src/procedures/terrain-styled-topology.ts +184 -0
  204. package/src/procedures/web-mercator-legacy.ts +24 -0
  205. package/src/procedures/web-mercator-math.ts +50 -0
  206. package/src/scene/camera.ts +298 -0
  207. package/src/scene/camera_base.ts +116 -0
  208. package/src/scene/classic_scene.ts +20 -0
  209. package/src/scene/external_camera.ts +101 -0
  210. package/src/scene/globals.ts +120 -0
  211. package/src/scene/ground_footprint.ts +139 -0
  212. package/src/scene/host_frame.ts +326 -0
  213. package/src/scene/projected_tile_lod.ts +125 -0
  214. package/src/scene/projection_math.ts +142 -0
  215. package/src/scene/projection_shaders.ts +183 -0
  216. package/src/scene/renderer.ts +516 -0
  217. package/src/scene/scene-resource-types.ts +174 -0
  218. package/src/scene/scene.ts +2378 -0
  219. package/src/scene/scene_bundle.ts +304 -0
  220. package/src/scene/scene_debug.ts +129 -0
  221. package/src/scene/scene_loader.ts +402 -0
  222. package/src/scene/scene_worker.ts +528 -0
  223. package/src/scene/view.ts +683 -0
  224. package/src/scene/visibility_adapter.ts +319 -0
  225. package/src/scene/worker_url.ts +15 -0
  226. package/src/selection/draped-terrain-surface.ts +377 -0
  227. package/src/selection/selection-types.ts +79 -0
  228. package/src/selection/selection.ts +542 -0
  229. package/src/selection/selection_fragment.glsl +18 -0
  230. package/src/selection/selection_globals.glsl +9 -0
  231. package/src/selection/selection_pixels.ts +59 -0
  232. package/src/selection/selection_vertex.glsl +15 -0
  233. package/src/selection/terrain_surface.ts +298 -0
  234. package/src/shader-modules/globe-horizon.ts +52 -0
  235. package/src/shader-modules/height-decode.ts +41 -0
  236. package/src/shader-modules/hillshade.ts +70 -0
  237. package/src/shader-modules/index.ts +10 -0
  238. package/src/shader-modules/planar.ts +24 -0
  239. package/src/shader-modules/sphere-map.ts +38 -0
  240. package/src/shader-modules/triplanar.ts +45 -0
  241. package/src/sources/aligned_tile_source.ts +122 -0
  242. package/src/sources/data_source.ts +655 -0
  243. package/src/sources/decoded_tile_store.ts +245 -0
  244. package/src/sources/geojson.ts +300 -0
  245. package/src/sources/mvt.ts +247 -0
  246. package/src/sources/raster.ts +341 -0
  247. package/src/sources/shared_tile_source_adapter.ts +117 -0
  248. package/src/sources/sources.ts +10 -0
  249. package/src/sources/tile_source_adapter.ts +84 -0
  250. package/src/sources/tile_source_metadata.ts +65 -0
  251. package/src/sources/tile_source_state.ts +112 -0
  252. package/src/sources/topojson.ts +90 -0
  253. package/src/styles/feature_annotations.ts +16 -0
  254. package/src/styles/filter.ts +190 -0
  255. package/src/styles/geometry-style-types.ts +209 -0
  256. package/src/styles/globe_visibility_wgsl.ts +22 -0
  257. package/src/styles/layer-types.ts +45 -0
  258. package/src/styles/layer.ts +586 -0
  259. package/src/styles/lines/dasharray.ts +49 -0
  260. package/src/styles/lines/lines.ts +707 -0
  261. package/src/styles/lines/lines_wgsl.ts +224 -0
  262. package/src/styles/points/point-runtime-types.ts +125 -0
  263. package/src/styles/points/points.ts +1079 -0
  264. package/src/styles/points/points_fragment.glsl +126 -0
  265. package/src/styles/points/points_vertex.glsl +230 -0
  266. package/src/styles/points/points_wgsl.ts +189 -0
  267. package/src/styles/polygons/polygons.ts +268 -0
  268. package/src/styles/polygons/polygons_fragment.glsl +173 -0
  269. package/src/styles/polygons/polygons_vertex.glsl +213 -0
  270. package/src/styles/polygons/polygons_wgsl.ts +127 -0
  271. package/src/styles/property-types.ts +125 -0
  272. package/src/styles/raster/raster.ts +33 -0
  273. package/src/styles/raster/raster_globals.glsl +46 -0
  274. package/src/styles/style-mixing-types.ts +101 -0
  275. package/src/styles/style-runtime-types.ts +220 -0
  276. package/src/styles/style-schema.ts +133 -0
  277. package/src/styles/style.ts +1033 -0
  278. package/src/styles/style_globals.glsl +69 -0
  279. package/src/styles/style_manager.ts +464 -0
  280. package/src/styles/style_parser.ts +620 -0
  281. package/src/styles/text/font_manager.ts +180 -0
  282. package/src/styles/text/fontfaceobserver.d.ts +10 -0
  283. package/src/styles/text/text-types.ts +220 -0
  284. package/src/styles/text/text.ts +378 -0
  285. package/src/styles/text/text_canvas.ts +773 -0
  286. package/src/styles/text/text_labels.ts +436 -0
  287. package/src/styles/text/text_segments.ts +142 -0
  288. package/src/styles/text/text_settings.ts +228 -0
  289. package/src/styles/text/text_wgsl.ts +159 -0
  290. package/src/styles/text/text_wrap.ts +194 -0
  291. package/src/tile/globe_tile_preload.ts +40 -0
  292. package/src/tile/tangram_tileset_2d.ts +108 -0
  293. package/src/tile/tile-build-types.ts +155 -0
  294. package/src/tile/tile.ts +807 -0
  295. package/src/tile/tile_id.ts +172 -0
  296. package/src/tile/tile_manager.ts +889 -0
  297. package/src/tile/tile_pyramid.ts +119 -0
  298. package/src/tile/tile_resource_cache.ts +91 -0
  299. package/src/tile/tile_traversal_adapter.ts +132 -0
  300. package/src/types.ts +332 -0
  301. package/src/utils/debounce.ts +17 -0
  302. package/src/utils/debug_settings.ts +43 -0
  303. package/src/utils/errors.ts +12 -0
  304. package/src/utils/functions.ts +95 -0
  305. package/src/utils/geo.ts +364 -0
  306. package/src/utils/hash.ts +14 -0
  307. package/src/utils/log.ts +108 -0
  308. package/src/utils/media_capture.ts +193 -0
  309. package/src/utils/merge.ts +44 -0
  310. package/src/utils/obb.ts +134 -0
  311. package/src/utils/props.ts +43 -0
  312. package/src/utils/slice.ts +14 -0
  313. package/src/utils/subscribe.ts +58 -0
  314. package/src/utils/task.ts +154 -0
  315. package/src/utils/thread.ts +26 -0
  316. package/src/utils/urls.ts +223 -0
  317. package/src/utils/utils.ts +310 -0
  318. package/src/utils/vector.ts +197 -0
  319. package/src/utils/version.ts +8 -0
  320. package/src/utils/worker-types.ts +79 -0
  321. package/src/utils/worker_broker.ts +523 -0
@@ -0,0 +1,436 @@
1
+ // Tangram
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) 2013-2016 Brett Camper and Mapzen
4
+ // Copyright (c) 2026 vis.gl contributors
5
+
6
+ // Text label rendering methods, can be mixed into a rendering style
7
+
8
+
9
+ import StyleParser from '../style_parser';
10
+ import type {LabelLayout} from '../../labels/label-types';
11
+ import type {TextSettingsResult} from './text_settings';
12
+ import type {TextLabelState, TextLabelDraw, TextFeature, TextContext, TextTile, TextFeatureQueue, TextLabelCandidate, ParsedTextFeature, TextTable, TextSourceValue, TextValue, TextAtlas} from './text-types';
13
+
14
+ /** Typed boundary to the legacy property-cache parser, not a replacement implementation. */
15
+ const typedStyleParser = StyleParser as unknown as {
16
+ createPropertyCache(value: unknown, parse?: (value: unknown) => unknown, interpolate?: (value: unknown) => unknown): unknown;
17
+ parsePositiveNumber(value: unknown): number;
18
+ parseNumber(value: unknown): number;
19
+ };
20
+ /** Host style state plus the checked text-label operations mixed into points/text. */
21
+ export type TextLabelRuntime = TextLabelState & TextLabelMethods;
22
+ /** Operations shared by standalone text and attached point text. */
23
+ export interface TextLabelMethods {
24
+ resetText(this: TextLabelRuntime): void;
25
+ freeText(this: TextLabelRuntime, tile: TextTile): void;
26
+ parseTextFeature(this: TextLabelRuntime, feature: TextFeature, draw: TextLabelDraw, context: TextContext, tile: TextTile): ParsedTextFeature | ParsedTextFeature[] | false | undefined;
27
+ parseTextSource(this: TextLabelRuntime, feature: TextFeature, draw: TextLabelDraw, context: TextContext): TextValue | Record<string, TextValue>;
28
+ parseTextSourceValue(this: TextLabelRuntime, source: TextSourceValue | TextSourceValue[], feature: TextFeature, context: TextContext): TextValue;
29
+ prepareTextLabels(this: TextLabelRuntime, tile: TextTile, queue: TextFeatureQueue[]): Promise<TextLabelCandidate[]>;
30
+ collideAndRenderTextLabels(this: TextLabelRuntime, tile: TextTile, group: string, queue: TextFeatureQueue[]): Promise<TextLabelResult>;
31
+ cullTextStyles(this: TextLabelRuntime, texts: TextTable, labels: TextLabelCandidate[]): void;
32
+ calcTextSizes(this: TextLabelRuntime, tileId: string, texts: TextTable): Promise<TextTable | undefined>;
33
+ rasterizeTexts(this: TextLabelRuntime, tileId: string, tileKey: string, texts: TextTable): Promise<TextLabelResult>;
34
+ preprocessText(this: TextLabelRuntime, draw: TextLabelDraw): TextLabelDraw | undefined;
35
+ computeTextLayout(this: TextLabelRuntime, target: Partial<LabelLayout>, feature: TextFeature, draw: TextLabelDraw, context: TextContext, tile: TextTile, text: TextValue, settings: TextSettingsResult, repeatGroup?: string, orientation?: string): LabelLayout;
36
+ }
37
+ /** Legacy broker boundary with explicit asynchronous payload types. */
38
+ const typedWorkerBroker = WorkerBroker;
39
+ /** Collision/rasterization may return no data after cancellation or teardown. */
40
+ export interface TextLabelResult {
41
+ labels?: TextLabelCandidate[];
42
+ texts?: TextTable;
43
+ textures?: string[];
44
+ }
45
+ import Geo from '../../utils/geo';
46
+ import log from '../../utils/log';
47
+ import Thread from '../../utils/thread';
48
+ import WorkerBroker from '../../utils/worker_broker';
49
+ import Collision from '../../labels/collision';
50
+ import TextSettings from '../text/text_settings';
51
+ import TextCanvas from './text_canvas';
52
+
53
+ // namespaces label textures (ensures new texture name when a tile is built multiple times)
54
+ let text_texture_id = 0;
55
+
56
+ export const TextLabels: TextLabelMethods = {
57
+
58
+ resetText (this: TextLabelRuntime): void {
59
+ if (Thread.is_main) {
60
+ this.canvas = new TextCanvas();
61
+ }
62
+ else if (Thread.is_worker) {
63
+ this.texts = {}; // unique texts, grouped by tile, by style
64
+ }
65
+ },
66
+
67
+ freeText (this: TextLabelRuntime, tile: TextTile): void {
68
+ delete this.texts[tile.id];
69
+ },
70
+
71
+ parseTextFeature (this: TextLabelRuntime, feature: TextFeature, draw: TextLabelDraw, context: TextContext, tile: TextTile): ParsedTextFeature | ParsedTextFeature[] | false | undefined {
72
+ // Compute label text
73
+ let text = this.parseTextSource(feature, draw, context);
74
+
75
+ if (text == null || text === '') {
76
+ return; // no text for this feature
77
+ }
78
+
79
+ // Compute text style and layout settings for this feature label
80
+ let text_settings = TextSettings.compute(draw, context);
81
+ let text_settings_key = TextSettings.key(text_settings);
82
+
83
+ // first label in tile, or with this style?
84
+ this.texts[tile.id] = this.texts[tile.id] || {};
85
+ let sizes = this.texts[tile.id][text_settings_key] = this.texts[tile.id][text_settings_key] || {};
86
+
87
+ if (text instanceof Object){
88
+ let results: ParsedTextFeature[] = [];
89
+
90
+ // add both left/right text elements to repeat group to improve repeat culling
91
+ // avoids one component of a boundary label (e.g. Colorado) being culled too aggressively when it also
92
+ // appears in nearby boundary labels (e.g. Colorado/Utah & Colorado/New Mexico repeat as separate groups)
93
+ let repeat_group_prefix = text.left + '-' + text.right; // NB: should be all text keys, not just left/right
94
+
95
+ for (let key in text){
96
+ let current_text = text[key];
97
+ if (!current_text) {
98
+ continue;
99
+ }
100
+
101
+ let layout = this.computeTextLayout({}, feature, draw, context, tile, current_text, text_settings, repeat_group_prefix, key);
102
+ if (!sizes[current_text as string]) {
103
+ // first label with this text/style/tile combination, make a new label entry
104
+ sizes[current_text as string] = {
105
+ text_settings,
106
+ ref: 0 // # of times this text/style combo appears in tile
107
+ };
108
+ }
109
+
110
+ results.push({
111
+ draw, text : current_text as string, text_settings_key, layout
112
+ });
113
+ }
114
+
115
+ return (results.length > 0 && results); // return null if no boundary labels found
116
+ }
117
+ else {
118
+ // unique text strings, grouped by text drawing style
119
+ let layout = this.computeTextLayout({}, feature, draw, context, tile, text, text_settings);
120
+ if (!sizes[text as string]) {
121
+ // first label with this text/style/tile combination, make a new label entry
122
+ sizes[text as string] = {
123
+ text_settings,
124
+ ref: 0 // # of times this text/style combo appears in tile
125
+ };
126
+ }
127
+
128
+ return {
129
+ draw, text: text as string, text_settings_key, layout
130
+ };
131
+ }
132
+ },
133
+
134
+ // Compute the label text, default is value of feature.properties.name
135
+ // - String value indicates a feature property look-up, e.g. `short_name` means use feature.properties.short_name
136
+ // - Function will use the return value as the label text (for custom labels)
137
+ // - Array (of strings and/or functions) defines a list of fallbacks, evaluated according to the above rules,
138
+ // with the first non-null value used as the label text
139
+ // e.g. `[name:es, name:en, name]` prefers Spanish names, followed by English, and last the default local name
140
+ parseTextSource (this: TextLabelRuntime, feature: TextFeature, draw: TextLabelDraw, context: TextContext): TextValue | Record<string, TextValue> {
141
+ let text: TextValue | Record<string, TextValue>;
142
+ let source = draw.text_source || 'name';
143
+
144
+ if (source != null && !Array.isArray(source) && typeof source === 'object') {
145
+ // left/right boundary labels
146
+ text = {};
147
+ for (let key in source) {
148
+ text[key] = this.parseTextSourceValue(source[key], feature, context);
149
+ }
150
+ }
151
+ else {
152
+ // single label
153
+ text = this.parseTextSourceValue(source, feature, context);
154
+ }
155
+
156
+ return text;
157
+ },
158
+
159
+ parseTextSourceValue (this: TextLabelRuntime, source: TextSourceValue | TextSourceValue[], feature: TextFeature, context: TextContext): TextValue {
160
+ let text: TextValue;
161
+ if (Array.isArray(source)) {
162
+ for (let s=0; s < source.length; s++) {
163
+ if (typeof source[s] === 'string') {
164
+ text = feature.properties[source[s] as string];
165
+ } else if (typeof source[s] === 'function') {
166
+ text = (source[s] as (context: TextContext) => TextValue)(context);
167
+ }
168
+
169
+ if (text) {
170
+ return text; // stop if we found a text property
171
+ }
172
+ }
173
+ }
174
+ else if (typeof source === 'string') {
175
+ text = feature.properties[source];
176
+ }
177
+ else if (source instanceof Function) {
178
+ text = source(context);
179
+ }
180
+
181
+ return text;
182
+ },
183
+
184
+ async prepareTextLabels (this: TextLabelRuntime, tile: TextTile, queue: TextFeatureQueue[]): Promise<TextLabelCandidate[]> {
185
+ if (Object.keys(this.texts[tile.id]||{}).length === 0) {
186
+ return [];
187
+ }
188
+
189
+ // first call to main thread, ask for text pixel sizes
190
+ try {
191
+ const texts = await typedWorkerBroker.postMessage<TextTable | undefined>(this.main_thread_target+'.calcTextSizes', tile.id, this.texts[tile.id]);
192
+ if (tile.canceled) {
193
+ log('trace', `Style ${this.name}: stop tile build because tile was canceled: ${tile.key}, post-calcTextSizes()`);
194
+ return [];
195
+ }
196
+
197
+ this.texts[tile.id] = texts || [] as unknown as TextTable;
198
+ if (!texts) {
199
+ Collision.abortTile(tile.id);
200
+ return [];
201
+ }
202
+
203
+ return this.buildTextLabels(tile, queue);
204
+ }
205
+ catch (e) { // error thrown if style has been removed from main thread
206
+ Collision.abortTile(tile.id);
207
+ return [];
208
+ }
209
+ },
210
+
211
+ async collideAndRenderTextLabels (this: TextLabelRuntime, tile: TextTile, collision_group: string, queue: TextFeatureQueue[]): Promise<TextLabelResult> {
212
+ let labels = await this.prepareTextLabels(tile, queue);
213
+ if (labels.length === 0) {
214
+ Collision.collide([], collision_group, tile.id);
215
+ return {};
216
+ }
217
+
218
+ labels = await Collision.collide(labels, collision_group, tile.id);
219
+ if (tile.canceled) {
220
+ log('trace', `stop tile build because tile was canceled: ${tile.key}, post-collide()`);
221
+ return {};
222
+ }
223
+
224
+ let texts = this.texts[tile.id];
225
+ if (texts == null || labels.length === 0) {
226
+ return {};
227
+ }
228
+
229
+ this.cullTextStyles(texts, labels);
230
+
231
+ // set alignments
232
+ labels.forEach(q => {
233
+ let text_settings_key = q.text_settings_key;
234
+ let text_info = texts[text_settings_key] && texts[text_settings_key][q.text];
235
+ if (!text_info.text_settings.can_articulate){
236
+ text_info.align = text_info.align || {};
237
+ text_info.align[q.label.align!] = {};
238
+ }
239
+ else {
240
+ // consider making it a set
241
+ if (!text_info.type) {
242
+ text_info.type = [];
243
+ }
244
+
245
+ if (text_info.type.indexOf(q.label.type) === -1){
246
+ text_info.type.push(q.label.type);
247
+ }
248
+ }
249
+ });
250
+
251
+ // second call to main thread, for rasterizing the set of texts
252
+ try {
253
+ const rasterized = await typedWorkerBroker.postMessage<TextLabelResult>(this.main_thread_target+'.rasterizeTexts', tile.id, tile.key, texts);
254
+ if (tile.canceled) {
255
+ log('trace', `stop tile build because tile was canceled: ${tile.key}, post-rasterizeTexts()`);
256
+ return {};
257
+ }
258
+ return { labels, ...rasterized };
259
+ }
260
+ catch (e) { // error thrown if style has been removed from main thread
261
+ return {};
262
+ }
263
+ },
264
+
265
+ // Remove unused text/style combinations to avoid unnecessary rasterization
266
+ cullTextStyles(this: TextLabelRuntime, texts: TextTable, labels: TextLabelCandidate[]): void {
267
+ // Count how many times each text/style combination is used
268
+ for (let i=0; i < labels.length; i++) {
269
+ let label = labels[i];
270
+ texts[label.text_settings_key][label.text].ref++;
271
+ }
272
+
273
+ // Remove text/style combinations that have no visible labels
274
+ for (let style in texts) {
275
+ for (let text in texts[style]) {
276
+ // no labels for this text
277
+ if (texts[style][text].ref < 1) {
278
+ delete texts[style][text];
279
+ }
280
+ }
281
+ }
282
+
283
+ for (let style in texts) {
284
+ // no labels for this style
285
+ if (Object.keys(texts[style]).length === 0) {
286
+ delete texts[style];
287
+ }
288
+ }
289
+ },
290
+
291
+ // Called on main thread from worker, to compute the size of each text string,
292
+ // were it to be rendered. This info is then used to perform initial label culling, *before*
293
+ // labels are actually rendered.
294
+ calcTextSizes (this: TextLabelRuntime, tile_id: string, texts: TextTable): Promise<TextTable | undefined> {
295
+ return this.canvas.textSizes(tile_id, texts);
296
+ },
297
+
298
+ // Called on main thread from worker, to create atlas of labels for a tile
299
+ async rasterizeTexts (this: TextLabelRuntime, tile_id: string, tile_key: string, texts: TextTable): Promise<TextLabelResult> {
300
+ let canvas = new TextCanvas(); // one per style per tile (style may be rendering multiple tiles at once)
301
+ let max_texture_size = Math.min(this.max_texture_size, 2048); // cap each label texture at 2048x2048
302
+
303
+ let textures: TextAtlas[] | string[] | undefined = canvas.setTextureTextPositions(texts, max_texture_size);
304
+ let texture_prefix = ['labels', this.name, tile_key, tile_id, text_texture_id, ''].join('-');
305
+ text_texture_id++;
306
+
307
+ textures = await canvas.rasterize(
308
+ texts,
309
+ textures,
310
+ tile_id,
311
+ texture_prefix,
312
+ this.resource_context
313
+ );
314
+ if (!textures) {
315
+ return {};
316
+ }
317
+ return { texts, textures };
318
+ },
319
+
320
+ preprocessText (this: TextLabelRuntime, draw: TextLabelDraw): TextLabelDraw | undefined {
321
+ // Font settings are required
322
+ if (!draw || !draw.font || typeof draw.font !== 'object') {
323
+ return;
324
+ }
325
+
326
+ // Font weight
327
+ draw.font.weight = typedStyleParser.createPropertyCache(draw.font.weight);
328
+
329
+ // Colors
330
+ draw.font.fill = typedStyleParser.createPropertyCache(draw.font.fill || TextSettings.defaults.fill);
331
+ draw.font.alpha = typedStyleParser.createPropertyCache(draw.font.alpha);
332
+
333
+ if (draw.font.stroke) {
334
+ draw.font.stroke.color = typedStyleParser.createPropertyCache(draw.font.stroke.color);
335
+ draw.font.stroke.alpha = typedStyleParser.createPropertyCache(draw.font.stroke.alpha);
336
+ }
337
+
338
+ if (draw.font.background) {
339
+ draw.font.background.color = typedStyleParser.createPropertyCache(draw.font.background.color);
340
+ draw.font.background.alpha = typedStyleParser.createPropertyCache(draw.font.background.alpha);
341
+ draw.font.background.width = typedStyleParser.createPropertyCache(draw.font.background.width, typedStyleParser.parsePositiveNumber);
342
+ if (draw.font.background.stroke) {
343
+ draw.font.background.stroke.color = typedStyleParser.createPropertyCache(draw.font.background.stroke.color);
344
+ draw.font.background.stroke.alpha = typedStyleParser.createPropertyCache(draw.font.background.stroke.alpha);
345
+ }
346
+ }
347
+
348
+ // Convert font and text stroke sizes
349
+ draw.font.px_size = typedStyleParser.createPropertyCache(draw.font.size || TextSettings.defaults.size, TextCanvas.fontPixelSize, TextCanvas.fontPixelSize);
350
+
351
+ if (draw.font.stroke && draw.font.stroke.width != null) {
352
+ draw.font.stroke.width = typedStyleParser.createPropertyCache(draw.font.stroke.width, typedStyleParser.parsePositiveNumber);
353
+ }
354
+
355
+ if (draw.font.background && draw.font.background.stroke && draw.font.background.stroke.width != null) {
356
+ draw.font.background.stroke.width = typedStyleParser.createPropertyCache(draw.font.background.stroke.width, typedStyleParser.parsePositiveNumber);
357
+ }
358
+
359
+ // Offset (2d array)
360
+ draw.offset = typedStyleParser.createPropertyCache(draw.offset,
361
+ v => Array.isArray(v) && v.map(typedStyleParser.parseNumber)
362
+ );
363
+
364
+ // Buffer (1d value or or 2d array) - must be >= 0
365
+ draw.buffer = typedStyleParser.createPropertyCache(draw.buffer,
366
+ v => (Array.isArray(v) ? v : [v, v]).map(typedStyleParser.parsePositiveNumber)
367
+ );
368
+
369
+ // Repeat rules - for text labels, defaults to tile size
370
+ draw.repeat_distance = typedStyleParser.createPropertyCache(
371
+ draw.repeat_distance,
372
+ typedStyleParser.parsePositiveNumber
373
+ );
374
+
375
+ return draw;
376
+ },
377
+
378
+ // Additional text-specific layout settings
379
+ computeTextLayout (this: TextLabelRuntime, target: Partial<LabelLayout>, feature: TextFeature, draw: TextLabelDraw, context: TextContext, tile: TextTile, text: TextValue, text_settings: TextSettingsResult, repeat_group_prefix?: string, orientation?: string): LabelLayout {
380
+ let layout: Partial<LabelLayout> = target || {};
381
+
382
+ // common settings w/points
383
+ layout = this.computeLayout(layout, feature, draw, context, tile);
384
+
385
+ // if draw group didn't specify repeat distance, override with text label-specific logic
386
+ if (draw.repeat_distance == null) {
387
+ // defaults: no limit on labels for point geometries, tile size (256px) limit for other geometries
388
+ layout.repeat_distance = (context.geometry === 'point' ? 0 : Geo.tile_size);
389
+
390
+ if (layout.repeat_distance) {
391
+ layout.repeat_distance *= layout.units_per_pixel!;
392
+ layout.repeat_scale = 1; // initial repeat pass in tile with full scale
393
+
394
+ if (typeof draw.repeat_group === 'function') {
395
+ layout.repeat_group = draw.repeat_group(context); // dynamic repeat group
396
+ }
397
+ else {
398
+ layout.repeat_group = draw.repeat_group; // pre-computed repeat group
399
+ }
400
+ }
401
+ }
402
+
403
+ // repeat rules include the text
404
+ if (layout.repeat_distance) {
405
+ if (repeat_group_prefix) {
406
+ layout.repeat_group += '/' + repeat_group_prefix;
407
+ }
408
+ layout.repeat_group += '/' + text;
409
+ }
410
+
411
+ // Max number of subdivisions to try
412
+ if (this.screen_space_labels || this.cpu_projection) {
413
+ // Preserve text identity even without IDs; position matching prevents unrelated names collapsing.
414
+ layout.projected_identity = JSON.stringify([layout.projected_identity ?? [context.source, context.layer,
415
+ this.name, draw.key], String(text)]);
416
+ }
417
+ layout.subdiv = tile.overzoom2;
418
+
419
+ layout.align = draw.align;
420
+
421
+ // used to fudge width value as text may overflow bounding box if it has italic, bold, etc style
422
+ // TODO rename to more generic, not italic-specific (bold)
423
+ layout.italic = (text_settings.style !== 'normal');
424
+
425
+ // used to determine orientation of text if the text_source has a `left` or `right` key
426
+ if (orientation === 'right') {
427
+ layout.orientation = 1;
428
+ }
429
+ else if (orientation === 'left'){
430
+ layout.orientation = -1;
431
+ }
432
+
433
+ return layout as LabelLayout;
434
+ }
435
+
436
+ };
@@ -0,0 +1,142 @@
1
+ // Tangram
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) 2013-2016 Brett Camper and Mapzen
4
+
5
+ // Text directionality (right-to-left, bi-directional) and segmentation (curved labels, Arabic handling)
6
+
7
+ // Right-to-left / bi-directional text handling
8
+ // Taken from http://stackoverflow.com/questions/12006095/javascript-how-to-check-if-character-is-rtl
9
+
10
+ type SegmentCache = {
11
+ segment: Record<string, string[]>;
12
+ stats: {
13
+ segment_hits: number;
14
+ segment_misses: number;
15
+ };
16
+ };
17
+
18
+ const rtl_test = new RegExp('[\u0591-\u07FF\u200F\u202B\u202E\uFB1D-\uFDFD\uFE70-\uFEFC]');
19
+ export function isTextRTL(s: string): boolean {
20
+ return rtl_test.test(s);
21
+ }
22
+
23
+ const neutral_chars = '\u0000-\u002F\u003A-\u0040\u005B-\u0060\u007B-\u00BF\u00D7\u00F7\u02B9-\u02FF\u2000-\u2BFF\u2010-\u2029\u202C\u202F-\u2BFF';
24
+ const neutral_test = new RegExp('['+neutral_chars+']+');
25
+ export function isTextNeutral(s: string): boolean {
26
+ return neutral_test.test(s);
27
+ }
28
+
29
+ export const RTL_MARKER = '\u200F'; // explicit right-to-left marker
30
+
31
+ // Arabic script ranges
32
+ // test http://localhost:8000/#16.72917/30.08541/31.28466
33
+ const arabic_range = new RegExp('^['+neutral_chars+'\u0600-\u06FF]+'); // all characters are Arabic or neutral
34
+ const arabic_splitters = new RegExp('['+neutral_chars+'\u0622-\u0625\u0627\u062F-\u0632\u0648\u0671-\u0677\u0688-\u0699\u06C4-\u06CB\u06CF\u06D2\u06D3\u06EE\u06EF]');
35
+ const arabic_vowels = new RegExp('^[\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED]+');
36
+
37
+ // Complex script ranges (non-Arabic)
38
+ const accents_and_vowels = '[\u0300-\u036F' + // Combining Diacritical Marks
39
+ '\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7' + // Hebrew
40
+ '\u07A6-\u07B0' + // Thaana
41
+ '\u0900-\u0903\u093A-\u094C\u094E\u094F\u0951-\u0957\u0962\u0963' + // Devanagari
42
+ '\u0981-\u0983\u09BC\u09BE-\u09CC\u09D7\u09E2\u09E3' + // Bengali
43
+ '\u0A01-\u0A03\u0A3C-\u0A4C\u0A51' + // Gurmukhi
44
+ '\u0A81-\u0A83\u0ABC\u0ABE-\u0ACC\u0AE2\u0AE3' + // Gujarati
45
+ '\u0B01-\u0B03\u0B3C\u0B3E-\u0B4C\u0B56\u0B57\u0B62\u0B63' + // Oriya
46
+ '\u0B82\u0BBE-\u0BCD\u0BD7' + // Tamil
47
+ '\u0C00-\u0C03\u0C3E-\u0C4C\u0C55\u0C56\u0C62\u0C63' + // Telugu
48
+ '\u0C81-\u0C83\u0CBC\u0CBE-\u0CCC\u0CD5\u0CD6\u0CE2\u0CE3' + // Kannada
49
+ '\u0D01-\u0D03\u0D3E-\u0D4C\u0D4E\u0D57\u0D62\u0D63' + // Malayalam
50
+ '\u0D82\u0D83\u0DCA-\u0DDF\u0DF2\u0DF3' + // Sinhala
51
+ '\u0E31\u0E34-\u0E3A\u0E47-\u0E4E' + // Thai
52
+ '\u0EB1\u0EB4-\u0EBC\u0EC8-\u0ECD' + // Lao
53
+ '\u0F18\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F83\u0F86\u0F87\u0F8D-\u0FBC\u0FC6' + // Tibetan
54
+ '\u102B-\u1038\u103A-\u103E\u1056-\u1059\u105E-\u1060\u1062-\u1064\u1067-\u106D\u1071-\u1074\u1082-\u108D\u108F\u109A-\u109D' + // Burmese
55
+ '\u17B4-\u17D1\u17D3' + // Khmer
56
+ '\u1A55-\u1A5E\u1A61-\u1A7C' + // Tai Tham
57
+ '\u1DC0-\u1DFF' + // Combining Diacritical Marks Supplement
58
+ '\u20D0-\u20FF' + // Combining Diacritical Marks for Symbols
59
+ ']';
60
+ const combo_characters = '[\u094D\u09CD\u0A4D\u0ACD\u0B4D\u0C4D\u0CCD\u0D4D\u0F84\u1039\u17D2\u1A60\u1A7F]';
61
+
62
+ // Find the next grapheme cluster (non-Arabic)
63
+ const grapheme_match = new RegExp(`^.(?:${accents_and_vowels}+)?(${combo_characters}\\W(?:${accents_and_vowels}+)?)*`); // eslint-disable-line no-misleading-character-class
64
+
65
+ // Scripts that cannot be curved due (due to contextual shaping and/or layout complexity)
66
+ const curve_blacklist: Record<string, string> = {
67
+ Mongolian: '\u1800-\u18AF'
68
+ };
69
+ const curve_blacklist_range = Object.keys(curve_blacklist).map(r => curve_blacklist[r]).join('');
70
+ const curve_blacklist_test = new RegExp('['+curve_blacklist_range+']');
71
+ export function isTextCurveBlacklisted(s: string): boolean {
72
+ return curve_blacklist_test.test(s);
73
+ }
74
+
75
+ // Splitting strategy for chopping a label into segments
76
+ const default_segment_length = 2; // character length of each segment when dividing up label text
77
+
78
+ export function splitLabelText(text: string, rtl: boolean, cache: SegmentCache): string[] {
79
+ // Use single-character segments for RTL, to avoid additional handling for neutral characters
80
+ // (see https://github.com/tangrams/tangram/issues/541)
81
+ const segment_length = rtl ? 1 : default_segment_length;
82
+
83
+ // Only one segment
84
+ if (text.length < segment_length) {
85
+ return [text];
86
+ }
87
+
88
+ // Check segment cache first (skips processing for labels we've seen before)
89
+ let key = text;
90
+ if (cache.segment[key]) {
91
+ cache.stats.segment_hits++;
92
+ return cache.segment[key];
93
+ }
94
+
95
+ let segments: string[] = [];
96
+
97
+ // Arabic-specific text handling
98
+ // NB: works for strings that are *only* Arabic; mixed-script labels may need more work
99
+ if (arabic_range.exec(text)) {
100
+ segments = text.split(arabic_splitters);
101
+ let offset = -1;
102
+ for (var s = 0; s < segments.length - 1; s++) {
103
+ if (s > 0) {
104
+ let carryover_vowels = arabic_vowels.exec(segments[s]);
105
+ if (carryover_vowels) {
106
+ segments[s] = segments[s].substring(carryover_vowels[0].length);
107
+ segments[s - 1] += carryover_vowels[0];
108
+ offset += carryover_vowels[0].length;
109
+ }
110
+ }
111
+ offset += 1 + segments[s].length;
112
+ segments[s] += text.slice(offset, offset + 1);
113
+ }
114
+ text = ''; // will skip non-Arabic handling below
115
+ }
116
+
117
+ // Non-Arabic text handling
118
+ while (text.length) {
119
+ let segment = '';
120
+ let test_text = text;
121
+ let grapheme_count = 0;
122
+
123
+ for (grapheme_count; grapheme_count < segment_length && test_text.length; grapheme_count++) {
124
+ let grapheme_cluster = (grapheme_match.exec(test_text) || test_text)[0];
125
+ segment += grapheme_cluster;
126
+ test_text = test_text.substring(grapheme_cluster.length);
127
+ }
128
+
129
+ segments.push(segment);
130
+ text = text.substring(segment.length);
131
+ }
132
+
133
+ // Reverse segments if needed
134
+ if (rtl) {
135
+ segments.reverse();
136
+ }
137
+
138
+ // Cache and return
139
+ cache.stats.segment_misses++;
140
+ cache.segment[key] = segments;
141
+ return segments;
142
+ }