@mapwhit/tilerenderer 1.4.0 → 1.5.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.
- package/build/min/package.json +1 -1
- package/package.json +1 -1
- package/src/data/bucket/symbol_bucket.js +25 -7
- package/src/index.js +23 -23
- package/src/source/rtl_text_plugin.js +133 -66
- package/src/source/worker_tile.js +2 -0
- package/src/style/evaluation_parameters.js +2 -3
- package/src/style/style.js +17 -11
- package/src/symbol/shaping.js +2 -2
- package/src/symbol/transform_text.js +3 -4
- package/src/util/config.js +1 -9
- package/src/util/script_detection.js +19 -7
package/build/min/package.json
CHANGED
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { dist } from '@mapwhit/point-geometry';
|
|
2
2
|
import { Formatted } from '@mapwhit/style-expressions';
|
|
3
3
|
import { VectorTileFeature } from '@mapwhit/vector-tile';
|
|
4
|
+
import { rtlPlugin } from '../../source/rtl_text_plugin.js';
|
|
4
5
|
import EvaluationParameters from '../../style/evaluation_parameters.js';
|
|
5
6
|
import mergeLines from '../../symbol/mergelines.js';
|
|
6
7
|
import { getSizeData } from '../../symbol/symbol_size.js';
|
|
7
8
|
import transformText from '../../symbol/transform_text.js';
|
|
8
|
-
import { allowsVerticalWritingMode } from '../../util/script_detection.js';
|
|
9
|
+
import { allowsVerticalWritingMode, stringContainsRTLText } from '../../util/script_detection.js';
|
|
9
10
|
import { verticalizedCharacterMap } from '../../util/verticalize_punctuation.js';
|
|
10
11
|
import {
|
|
11
12
|
CollisionBoxLayoutArray,
|
|
@@ -44,6 +45,15 @@ export function addDynamicAttributes(dynamicLayoutVertexArray, p, angle) {
|
|
|
44
45
|
dynamicLayoutVertexArray.emplaceBack(p.x, p.y, angle);
|
|
45
46
|
}
|
|
46
47
|
|
|
48
|
+
function containsRTLText(formattedText) {
|
|
49
|
+
for (const section of formattedText.sections) {
|
|
50
|
+
if (stringContainsRTLText(section.text)) {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
|
|
47
57
|
/**
|
|
48
58
|
* Unlike other buckets, which simply implement #addFeature with type-specific
|
|
49
59
|
* logic for (essentially) triangulating feature geometries, SymbolBucket
|
|
@@ -86,6 +96,7 @@ export default class SymbolBucket {
|
|
|
86
96
|
this.pixelRatio = options.pixelRatio;
|
|
87
97
|
this.sourceLayerIndex = options.sourceLayerIndex;
|
|
88
98
|
this.hasPattern = false;
|
|
99
|
+
this.hasRTLText = false;
|
|
89
100
|
this.sortKeyRanges = [];
|
|
90
101
|
|
|
91
102
|
const layer = this.layers[0];
|
|
@@ -169,11 +180,16 @@ export default class SymbolBucket {
|
|
|
169
180
|
// but plain string token evaluation skips that pathway so do the
|
|
170
181
|
// conversion here.
|
|
171
182
|
const resolvedTokens = layer.getValueAndResolveTokens('text-field', feature);
|
|
172
|
-
|
|
173
|
-
resolvedTokens instanceof Formatted ? resolvedTokens : Formatted.fromString(resolvedTokens)
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
183
|
+
const formattedText =
|
|
184
|
+
resolvedTokens instanceof Formatted ? resolvedTokens : Formatted.fromString(resolvedTokens);
|
|
185
|
+
// on this instance: if hasRTLText is already true, all future calls to containsRTLText can be skipped.
|
|
186
|
+
const bucketHasRTLText = (this.hasRTLText = this.hasRTLText || containsRTLText(formattedText));
|
|
187
|
+
if (
|
|
188
|
+
!bucketHasRTLText || // non-rtl text so can proceed safely
|
|
189
|
+
rtlPlugin.isRTLSupported(true) // Use the rtlText plugin to shape text if available or We don't intend to lazy-load the rtl text plugin, so proceed with incorrect shaping
|
|
190
|
+
) {
|
|
191
|
+
text = transformText(formattedText, layer, feature);
|
|
192
|
+
}
|
|
177
193
|
}
|
|
178
194
|
|
|
179
195
|
let icon;
|
|
@@ -244,7 +260,9 @@ export default class SymbolBucket {
|
|
|
244
260
|
}
|
|
245
261
|
|
|
246
262
|
isEmpty() {
|
|
247
|
-
|
|
263
|
+
// When the bucket encounters only rtl-text but the plugin isnt loaded, no symbol instances will be created.
|
|
264
|
+
// In order for the bucket to be serialized, and not discarded as an empty bucket both checks are necessary.
|
|
265
|
+
return this.symbolInstances.length === 0 && !this.hasRTLText;
|
|
248
266
|
}
|
|
249
267
|
|
|
250
268
|
uploadPending() {
|
package/src/index.js
CHANGED
|
@@ -5,20 +5,21 @@ import { Point } from '@mapwhit/point-geometry';
|
|
|
5
5
|
import packageJSON from '../package.json' with { type: 'json' };
|
|
6
6
|
import { default as LngLat } from './geo/lng_lat.js';
|
|
7
7
|
import { default as LngLatBounds } from './geo/lng_lat_bounds.js';
|
|
8
|
-
import {
|
|
8
|
+
import { rtlPluginLoader } from './source/rtl_text_plugin.js';
|
|
9
9
|
import { default as Style } from './style/style.js';
|
|
10
10
|
import { default as Map } from './ui/map.js';
|
|
11
11
|
import config from './util/config.js';
|
|
12
12
|
|
|
13
13
|
const { version } = packageJSON;
|
|
14
14
|
|
|
15
|
-
export { version, config, setRTLTextPlugin, Point, LngLat, LngLatBounds, Style, Map, Evented };
|
|
15
|
+
export { version, config, setRTLTextPlugin, getRTLTextPluginStatus, Point, LngLat, LngLatBounds, Style, Map, Evented };
|
|
16
16
|
|
|
17
17
|
// for commonjs backward compatibility
|
|
18
18
|
const mapwhit = {
|
|
19
19
|
version,
|
|
20
20
|
config,
|
|
21
21
|
setRTLTextPlugin,
|
|
22
|
+
getRTLTextPluginStatus,
|
|
22
23
|
Point,
|
|
23
24
|
LngLat,
|
|
24
25
|
LngLatBounds,
|
|
@@ -27,24 +28,7 @@ const mapwhit = {
|
|
|
27
28
|
Evented
|
|
28
29
|
};
|
|
29
30
|
|
|
30
|
-
const properties = {
|
|
31
|
-
workerCount: {
|
|
32
|
-
get() {
|
|
33
|
-
return config.WORKER_COUNT;
|
|
34
|
-
},
|
|
35
|
-
set(count) {
|
|
36
|
-
config.WORKER_COUNT = count;
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
workerUrl: {
|
|
40
|
-
get() {
|
|
41
|
-
return config.WORKER_URL;
|
|
42
|
-
},
|
|
43
|
-
set(url) {
|
|
44
|
-
config.WORKER_URL = url;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
};
|
|
31
|
+
const properties = {};
|
|
48
32
|
|
|
49
33
|
Object.defineProperties(mapwhit, properties);
|
|
50
34
|
Object.defineProperties(config, properties);
|
|
@@ -64,11 +48,27 @@ export default mapwhit;
|
|
|
64
48
|
*
|
|
65
49
|
* @function setRTLTextPlugin
|
|
66
50
|
* @param {string} pluginURL URL pointing to the Mapbox RTL text plugin source.
|
|
67
|
-
* @param {
|
|
51
|
+
* @param {boolean} lazy If set to `true`, mapboxgl will defer loading the plugin until rtl text is encountered,
|
|
52
|
+
* rtl text will then be rendered only after the plugin finishes loading.
|
|
53
|
+
* @example
|
|
54
|
+
* setRTLTextPlugin('https://unpkg.com/@mapbox/mapbox-gl-rtl-text@0.3.0/dist/mapbox-gl-rtl-text.js', false);
|
|
55
|
+
* @see [Add support for right-to-left scripts](https://maplibre.org/maplibre-gl-js/docs/examples/mapbox-gl-rtl-text/)
|
|
56
|
+
*/
|
|
57
|
+
function setRTLTextPlugin(pluginURL, lazy) {
|
|
58
|
+
return rtlPluginLoader.setRTLTextPlugin(pluginURL, lazy);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Gets the map's [RTL text plugin](https://www.mapbox.com/mapbox-gl-js/plugins/#mapbox-gl-rtl-text) status.
|
|
62
|
+
* The status can be `unavailable` (i.e. not requested or removed), `loading`, `loaded` or `error`.
|
|
63
|
+
* If the status is `loaded` and the plugin is requested again, an error will be thrown.
|
|
64
|
+
*
|
|
65
|
+
* @function getRTLTextPluginStatus
|
|
68
66
|
* @example
|
|
69
|
-
*
|
|
70
|
-
* @see [Add support for right-to-left scripts](https://www.mapbox.com/mapbox-gl-js/example/mapbox-gl-rtl-text/)
|
|
67
|
+
* const pluginStatus = getRTLTextPluginStatus();
|
|
71
68
|
*/
|
|
69
|
+
function getRTLTextPluginStatus() {
|
|
70
|
+
return rtlPluginLoader.getRTLTextPluginStatus();
|
|
71
|
+
}
|
|
72
72
|
|
|
73
73
|
// canary assert: used to confirm that asserts have been removed from production build
|
|
74
74
|
import assert from 'assert';
|
|
@@ -1,82 +1,145 @@
|
|
|
1
|
+
import { Event, Evented } from '@mapwhit/events';
|
|
1
2
|
import dynload from 'dynload';
|
|
2
3
|
import browser from '../util/browser.js';
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
/**
|
|
6
|
+
* The possible option of the plugin's status
|
|
7
|
+
*
|
|
8
|
+
* `unavailable`: Not loaded.
|
|
9
|
+
*
|
|
10
|
+
* `deferred`: The plugin URL has been specified, but loading has been deferred.
|
|
11
|
+
*
|
|
12
|
+
* `loading`: request in-flight.
|
|
13
|
+
*
|
|
14
|
+
* `loaded`: The plugin is now loaded
|
|
15
|
+
*
|
|
16
|
+
* `error`: The plugin failed to load
|
|
17
|
+
*/
|
|
7
18
|
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
clearRTLTextPlugin, // exported for testing
|
|
13
|
-
loadScript, // exported for testing
|
|
14
|
-
registerForPluginAvailability,
|
|
15
|
-
setRTLTextPlugin
|
|
16
|
-
};
|
|
19
|
+
function RTLPlugin() {
|
|
20
|
+
const self = {
|
|
21
|
+
isRTLSupported
|
|
22
|
+
};
|
|
17
23
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Checks whether the RTL language support is available.
|
|
26
|
+
* If `canChangeShortly` is false, it will only return true if the RTL language
|
|
27
|
+
* is properly supported.
|
|
28
|
+
* If `canChangeShortly` is true, it will also return true if the RTL language
|
|
29
|
+
* is not supported unless it can obtain the RTL text plugin.
|
|
30
|
+
* @param {boolean} canChangeShortly
|
|
31
|
+
* @returns
|
|
32
|
+
*/
|
|
33
|
+
function isRTLSupported(canChangeShortly) {
|
|
34
|
+
if (rtlPluginLoader.getRTLTextPluginStatus() === 'loaded') {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
if (!canChangeShortly) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
rtlPluginLoader.lazyLoad();
|
|
41
|
+
// any transitive state other than 'loading' means we can consider RTL supported as best as possible for now
|
|
42
|
+
return rtlPluginLoader.getRTLTextPluginStatus() !== 'loading';
|
|
22
43
|
}
|
|
23
|
-
_loadedCallbacks.push(callback);
|
|
24
|
-
loadRTLTextPlugin();
|
|
25
|
-
return () => _loadedCallbacks.splice(_loadedCallbacks.indexOf(callback), 1);
|
|
26
|
-
}
|
|
27
44
|
|
|
28
|
-
|
|
29
|
-
_loadedCallbacks.length = 0;
|
|
30
|
-
pluginRequested = false;
|
|
31
|
-
pluginURL = undefined;
|
|
45
|
+
return self;
|
|
32
46
|
}
|
|
33
47
|
|
|
34
|
-
export
|
|
35
|
-
|
|
36
|
-
|
|
48
|
+
export const rtlPlugin = RTLPlugin();
|
|
49
|
+
|
|
50
|
+
function RTLPluginLoader() {
|
|
51
|
+
let status = 'unavailable';
|
|
52
|
+
let url;
|
|
53
|
+
|
|
54
|
+
const self = {
|
|
55
|
+
getRTLTextPluginStatus,
|
|
56
|
+
setRTLTextPlugin,
|
|
57
|
+
lazyLoad,
|
|
58
|
+
_clearRTLTextPlugin,
|
|
59
|
+
_registerRTLTextPlugin
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/** This one is exposed to outside */
|
|
63
|
+
function getRTLTextPluginStatus() {
|
|
64
|
+
return status;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// public for testing
|
|
68
|
+
function _clearRTLTextPlugin() {
|
|
69
|
+
url = undefined;
|
|
70
|
+
status = 'unavailable';
|
|
71
|
+
_setMethods();
|
|
37
72
|
}
|
|
38
|
-
|
|
39
|
-
pluginURL =
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
73
|
+
|
|
74
|
+
function setRTLTextPlugin(pluginURL, deferred = false) {
|
|
75
|
+
if (url) {
|
|
76
|
+
// error
|
|
77
|
+
return Promise.reject(new Error('setRTLTextPlugin cannot be called multiple times.'));
|
|
78
|
+
}
|
|
79
|
+
url = browser.resolveURL(pluginURL);
|
|
80
|
+
if (!url) {
|
|
81
|
+
return Promise.reject(new Error(`requested url ${pluginURL} is invalid`));
|
|
82
|
+
}
|
|
83
|
+
if (status === 'requested') {
|
|
84
|
+
return _downloadRTLTextPlugin();
|
|
85
|
+
}
|
|
86
|
+
if (status === 'unavailable') {
|
|
87
|
+
// from initial state:
|
|
88
|
+
if (!deferred) {
|
|
89
|
+
return _downloadRTLTextPlugin();
|
|
47
90
|
}
|
|
91
|
+
status = 'deferred';
|
|
48
92
|
}
|
|
49
|
-
|
|
50
|
-
_completionCallback = undefined;
|
|
51
|
-
};
|
|
52
|
-
loadRTLTextPlugin();
|
|
53
|
-
}
|
|
93
|
+
}
|
|
54
94
|
|
|
55
|
-
function
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
95
|
+
async function _downloadRTLTextPlugin() {
|
|
96
|
+
status = 'loading';
|
|
97
|
+
try {
|
|
98
|
+
await rtlPluginLoader._loadScript({ url });
|
|
99
|
+
} catch {
|
|
100
|
+
status = 'error';
|
|
101
|
+
}
|
|
102
|
+
rtlPluginLoader.fire(new Event('RTLPluginLoaded'));
|
|
59
103
|
}
|
|
60
|
-
}
|
|
61
104
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
105
|
+
/** Start a lazy loading process of RTL plugin */
|
|
106
|
+
function lazyLoad() {
|
|
107
|
+
if (status === 'unavailable') {
|
|
108
|
+
status = 'requested';
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (status === 'deferred') {
|
|
112
|
+
return _downloadRTLTextPlugin();
|
|
113
|
+
}
|
|
65
114
|
}
|
|
66
|
-
plugin['applyArabicShaping'] = loadedPlugin.applyArabicShaping;
|
|
67
|
-
plugin['processBidirectionalText'] = loadedPlugin.processBidirectionalText;
|
|
68
|
-
plugin['processStyledBidirectionalText'] = loadedPlugin.processStyledBidirectionalText;
|
|
69
115
|
|
|
70
|
-
|
|
71
|
-
|
|
116
|
+
function _setMethods(rtlTextPlugin) {
|
|
117
|
+
if (!rtlTextPlugin) {
|
|
118
|
+
// for testing only
|
|
119
|
+
rtlPlugin.processStyledBidirectionalText = null;
|
|
120
|
+
rtlPlugin.processBidirectionalText = null;
|
|
121
|
+
rtlPlugin.applyArabicShaping = null;
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
rtlPlugin.applyArabicShaping = rtlTextPlugin.applyArabicShaping;
|
|
125
|
+
rtlPlugin.processBidirectionalText = rtlTextPlugin.processBidirectionalText;
|
|
126
|
+
rtlPlugin.processStyledBidirectionalText = rtlTextPlugin.processStyledBidirectionalText;
|
|
72
127
|
}
|
|
73
|
-
_loadedCallbacks.forEach(callback => callback());
|
|
74
|
-
_loadedCallbacks.length = 0;
|
|
75
|
-
}
|
|
76
128
|
|
|
77
|
-
|
|
129
|
+
// This is invoked by the RTL text plugin when the download has finished, and the code has been parsed.
|
|
130
|
+
function _registerRTLTextPlugin(rtlTextPlugin) {
|
|
131
|
+
if (rtlPlugin.isRTLSupported()) {
|
|
132
|
+
throw new Error('RTL text plugin already registered.');
|
|
133
|
+
}
|
|
134
|
+
status = 'loaded';
|
|
135
|
+
_setMethods(rtlTextPlugin);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return self;
|
|
139
|
+
}
|
|
78
140
|
|
|
79
|
-
|
|
141
|
+
// public for testing
|
|
142
|
+
function _loadScript({ url }) {
|
|
80
143
|
const { promise, resolve, reject } = Promise.withResolvers();
|
|
81
144
|
const s = dynload(url);
|
|
82
145
|
s.onload = () => resolve();
|
|
@@ -84,11 +147,15 @@ function loadScript(url) {
|
|
|
84
147
|
return promise;
|
|
85
148
|
}
|
|
86
149
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
isLoaded: () => plugin.applyArabicShaping != null
|
|
92
|
-
});
|
|
150
|
+
const { getRTLTextPluginStatus, setRTLTextPlugin, lazyLoad, _clearRTLTextPlugin, _registerRTLTextPlugin } =
|
|
151
|
+
RTLPluginLoader();
|
|
152
|
+
|
|
153
|
+
globalThis.registerRTLTextPlugin ??= _registerRTLTextPlugin;
|
|
93
154
|
|
|
94
|
-
export
|
|
155
|
+
export const rtlPluginLoader = Object.assign(new Evented(), {
|
|
156
|
+
getRTLTextPluginStatus,
|
|
157
|
+
setRTLTextPlugin,
|
|
158
|
+
lazyLoad,
|
|
159
|
+
_clearRTLTextPlugin,
|
|
160
|
+
_loadScript
|
|
161
|
+
});
|
|
@@ -148,6 +148,8 @@ async function finalizeBuckets(params, options, resources) {
|
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
async function makeAtlasses({ glyphDependencies, patternDependencies, iconDependencies }, resources) {
|
|
151
|
+
// options.glyphDependencies looks like: {"SomeFontName":{"10":true,"32":true}}
|
|
152
|
+
// this line makes an object like: {"SomeFontName":[10,32]}
|
|
151
153
|
const stacks = mapObject(glyphDependencies, glyphs => Object.keys(glyphs).map(Number));
|
|
152
154
|
const icons = Object.keys(iconDependencies);
|
|
153
155
|
const patterns = Object.keys(patternDependencies);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { rtlPlugin } from '../source/rtl_text_plugin.js';
|
|
2
2
|
import { isStringInSupportedScript } from '../util/script_detection.js';
|
|
3
3
|
import ZoomHistory from './zoom_history.js';
|
|
4
4
|
|
|
@@ -20,7 +20,6 @@ export default class EvaluationParameters {
|
|
|
20
20
|
this.transition = {};
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
-
|
|
24
23
|
crossFadingFactor() {
|
|
25
24
|
if (this.fadeDuration === 0) {
|
|
26
25
|
return 1;
|
|
@@ -40,5 +39,5 @@ export default class EvaluationParameters {
|
|
|
40
39
|
}
|
|
41
40
|
|
|
42
41
|
function isSupportedScript(str) {
|
|
43
|
-
return isStringInSupportedScript(str,
|
|
42
|
+
return isStringInSupportedScript(str, rtlPlugin.isRTLSupported());
|
|
44
43
|
}
|
package/src/style/style.js
CHANGED
|
@@ -5,7 +5,7 @@ import ImageManager from '../render/image_manager.js';
|
|
|
5
5
|
import LineAtlas from '../render/line_atlas.js';
|
|
6
6
|
import { queryRenderedFeatures, queryRenderedSymbols, querySourceFeatures } from '../source/query_features.js';
|
|
7
7
|
import { resources } from '../source/resources/index.js';
|
|
8
|
-
import
|
|
8
|
+
import { rtlPluginLoader } from '../source/rtl_text_plugin.js';
|
|
9
9
|
import { getType as getSourceType, setType as setSourceType } from '../source/source.js';
|
|
10
10
|
import SourceCache from '../source/source_cache.js';
|
|
11
11
|
import CrossTileSymbolIndex from '../symbol/cross_tile_symbol_index.js';
|
|
@@ -42,6 +42,7 @@ class Style extends Evented {
|
|
|
42
42
|
});
|
|
43
43
|
#layerIndex = new StyleLayerIndex();
|
|
44
44
|
#opsQueue = [];
|
|
45
|
+
#rtlPluginLoadedHandler;
|
|
45
46
|
|
|
46
47
|
constructor(map, options = {}) {
|
|
47
48
|
super();
|
|
@@ -63,9 +64,8 @@ class Style extends Evented {
|
|
|
63
64
|
this._updatedLayers = new Map();
|
|
64
65
|
this._removedLayers = new Map();
|
|
65
66
|
this._resetUpdates();
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
this.#rtlPluginLoadedHandler = this.#rtlPluginLoaded.bind(this);
|
|
68
|
+
rtlPluginLoader.on('RTLPluginLoaded', this.#rtlPluginLoadedHandler);
|
|
69
69
|
this.on('data', event => {
|
|
70
70
|
if (event.dataType !== 'source' || event.sourceDataType !== 'metadata') {
|
|
71
71
|
return;
|
|
@@ -89,6 +89,18 @@ class Style extends Evented {
|
|
|
89
89
|
});
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
#rtlPluginLoaded() {
|
|
93
|
+
for (const sourceCache of Object.values(this._sources)) {
|
|
94
|
+
const { type } = sourceCache.getSource();
|
|
95
|
+
if (type === 'vector' || type === 'geojson') {
|
|
96
|
+
// Non-vector sources don't have any symbols buckets to reload when the RTL text plugin loads
|
|
97
|
+
// They also load more quickly, so they're more likely to have already displaying tiles
|
|
98
|
+
// that would be unnecessarily booted by the plugin load event
|
|
99
|
+
sourceCache.reload(); // Should be a no-op if the plugin loads before any tiles load
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
92
104
|
setGlobalStateProperty(name, value) {
|
|
93
105
|
if (!this._loaded) {
|
|
94
106
|
this.#opsQueue.push(() => this.setGlobalStateProperty(name, value));
|
|
@@ -1043,7 +1055,7 @@ class Style extends Evented {
|
|
|
1043
1055
|
}
|
|
1044
1056
|
|
|
1045
1057
|
_remove() {
|
|
1046
|
-
|
|
1058
|
+
rtlPluginLoader.off('RTLPluginLoaded', this.#rtlPluginLoadedHandler);
|
|
1047
1059
|
for (const id in this._sources) {
|
|
1048
1060
|
this._sources[id].clearTiles();
|
|
1049
1061
|
}
|
|
@@ -1064,12 +1076,6 @@ class Style extends Evented {
|
|
|
1064
1076
|
}
|
|
1065
1077
|
}
|
|
1066
1078
|
|
|
1067
|
-
_reloadSources() {
|
|
1068
|
-
for (const sourceCache of Object.values(this._sources)) {
|
|
1069
|
-
sourceCache.reload(); // Should be a no-op if called before any tiles load
|
|
1070
|
-
}
|
|
1071
|
-
}
|
|
1072
|
-
|
|
1073
1079
|
_generateCollisionBoxes() {
|
|
1074
1080
|
for (const id in this._sources) {
|
|
1075
1081
|
this._reloadSource(id);
|
package/src/symbol/shaping.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { rtlPlugin } from '../source/rtl_text_plugin.js';
|
|
2
2
|
import { charAllowsIdeographicBreaking, charHasUprightVerticalOrientation } from '../util/script_detection.js';
|
|
3
3
|
import verticalizePunctuation from '../util/verticalize_punctuation.js';
|
|
4
4
|
import ONE_EM from './one_em.js';
|
|
@@ -112,7 +112,7 @@ export function shapeText(
|
|
|
112
112
|
|
|
113
113
|
let lines;
|
|
114
114
|
|
|
115
|
-
const { processBidirectionalText, processStyledBidirectionalText } =
|
|
115
|
+
const { processBidirectionalText, processStyledBidirectionalText } = rtlPlugin;
|
|
116
116
|
if (processBidirectionalText && logicalInput.sections.length === 1) {
|
|
117
117
|
// Bidi doesn't have to be style-aware
|
|
118
118
|
lines = [];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { rtlPlugin } from '../source/rtl_text_plugin.js';
|
|
2
2
|
|
|
3
3
|
function transformText(text, layer, feature) {
|
|
4
4
|
const transform = layer._layout.get('text-transform').evaluate(feature, {});
|
|
@@ -7,9 +7,8 @@ function transformText(text, layer, feature) {
|
|
|
7
7
|
} else if (transform === 'lowercase') {
|
|
8
8
|
text = text.toLocaleLowerCase();
|
|
9
9
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
text = rtlTextPlugin.applyArabicShaping(text);
|
|
10
|
+
if (rtlPlugin.applyArabicShaping) {
|
|
11
|
+
text = rtlPlugin.applyArabicShaping(text);
|
|
13
12
|
}
|
|
14
13
|
|
|
15
14
|
return text;
|
package/src/util/config.js
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
import { Evented } from '@mapwhit/events';
|
|
2
|
-
import browser from './browser.js';
|
|
3
|
-
|
|
4
|
-
function getDefaultWorkerCount() {
|
|
5
|
-
return Math.max(Math.floor(browser.hardwareConcurrency / 2), 1);
|
|
6
|
-
}
|
|
7
2
|
|
|
8
3
|
const config = new Evented();
|
|
9
4
|
|
|
@@ -18,7 +13,4 @@ config.notify = function () {
|
|
|
18
13
|
config.fire('change', config);
|
|
19
14
|
};
|
|
20
15
|
|
|
21
|
-
config.set({
|
|
22
|
-
WORKER_COUNT: getDefaultWorkerCount(),
|
|
23
|
-
WORKER_URL: ''
|
|
24
|
-
});
|
|
16
|
+
config.set({});
|
|
@@ -415,6 +415,15 @@ export function charHasRotatedVerticalOrientation(char) {
|
|
|
415
415
|
return !(charHasUprightVerticalOrientation(char) || charHasNeutralVerticalOrientation(char));
|
|
416
416
|
}
|
|
417
417
|
|
|
418
|
+
export function charInRTLScript(char) {
|
|
419
|
+
// Main blocks for Hebrew, Arabic, Thaana and other RTL scripts
|
|
420
|
+
return (
|
|
421
|
+
(char >= 0x0590 && char <= 0x08ff) ||
|
|
422
|
+
isChar['Arabic Presentation Forms-A'](char) ||
|
|
423
|
+
isChar['Arabic Presentation Forms-B'](char)
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
|
|
418
427
|
export function charInSupportedScript(char, canRenderRTL) {
|
|
419
428
|
// This is a rough heuristic: whether we "can render" a script
|
|
420
429
|
// actually depends on the properties of the font being used
|
|
@@ -423,13 +432,7 @@ export function charInSupportedScript(char, canRenderRTL) {
|
|
|
423
432
|
|
|
424
433
|
// Even in Latin script, we "can't render" combinations such as the fi
|
|
425
434
|
// ligature, but we don't consider that semantically significant.
|
|
426
|
-
if (
|
|
427
|
-
!canRenderRTL &&
|
|
428
|
-
((char >= 0x0590 && char <= 0x08ff) ||
|
|
429
|
-
isChar['Arabic Presentation Forms-A'](char) ||
|
|
430
|
-
isChar['Arabic Presentation Forms-B'](char))
|
|
431
|
-
) {
|
|
432
|
-
// Main blocks for Hebrew, Arabic, Thaana and other RTL scripts
|
|
435
|
+
if (!canRenderRTL && charInRTLScript(char)) {
|
|
433
436
|
return false;
|
|
434
437
|
}
|
|
435
438
|
if (
|
|
@@ -448,6 +451,15 @@ export function charInSupportedScript(char, canRenderRTL) {
|
|
|
448
451
|
return true;
|
|
449
452
|
}
|
|
450
453
|
|
|
454
|
+
export function stringContainsRTLText(chars) {
|
|
455
|
+
for (const char of chars) {
|
|
456
|
+
if (charInRTLScript(char.charCodeAt(0))) {
|
|
457
|
+
return true;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
return false;
|
|
461
|
+
}
|
|
462
|
+
|
|
451
463
|
export function isStringInSupportedScript(chars, canRenderRTL) {
|
|
452
464
|
for (const char of chars) {
|
|
453
465
|
if (!charInSupportedScript(char.charCodeAt(0), canRenderRTL)) {
|