Avoid try/catch, DOM and workers
This commit is contained in:
@@ -4,10 +4,13 @@
|
||||
|
||||
/**
|
||||
* @typedef {Object} FontParameters
|
||||
* @property {Array<string>} families
|
||||
* @property {string} style
|
||||
* @property {string} variant
|
||||
* @property {string} weight
|
||||
* @property {string} size
|
||||
* @property {string} lineHeight
|
||||
* @property {string} family
|
||||
* @property {Array<string>} families
|
||||
*/
|
||||
|
||||
|
||||
@@ -65,42 +68,52 @@ export const CLASS_CONTROL = 'ol-control';
|
||||
*/
|
||||
export const CLASS_COLLAPSED = 'ol-collapsed';
|
||||
|
||||
/**
|
||||
* From http://stackoverflow.com/questions/10135697/regex-to-parse-any-css-font
|
||||
* @type {RegExp}
|
||||
*/
|
||||
const fontRegEx = new RegExp([
|
||||
'^\\s*(?=(?:(?:[-a-z]+\\s*){0,2}(italic|oblique))?)',
|
||||
'(?=(?:(?:[-a-z]+\\s*){0,2}(small-caps))?)',
|
||||
'(?=(?:(?:[-a-z]+\\s*){0,2}(bold(?:er)?|lighter|[1-9]00 ))?)',
|
||||
'(?:(?:normal|\\1|\\2|\\3)\\s*){0,3}((?:xx?-)?',
|
||||
'(?:small|large)|medium|smaller|larger|[\\.\\d]+(?:\\%|in|[cem]m|ex|p[ctx]))',
|
||||
'(?:\\s*\\/\\s*(normal|[\\.\\d]+(?:\\%|in|[cem]m|ex|p[ctx])?))',
|
||||
'?\\s*([-,\\"\\\'\\sa-z]+?)\\s*$'
|
||||
].join(''), 'i');
|
||||
const fontRegExMatchIndex = [
|
||||
'style',
|
||||
'variant',
|
||||
'weight',
|
||||
'size',
|
||||
'lineHeight',
|
||||
'family'
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the list of font families from a font spec. Note that this doesn't work
|
||||
* for font families that have commas in them.
|
||||
* @param {string} fontSpec The CSS font property.
|
||||
* @param {function(FontParameters):void} callback Called with the font families
|
||||
* (or null if the input spec is invalid).
|
||||
* @return {FontParameters} The font parameters (or null if the input spec is invalid).
|
||||
*/
|
||||
export const getFontParameters = (function() {
|
||||
/**
|
||||
* @type {CSSStyleDeclaration}
|
||||
*/
|
||||
let style;
|
||||
/**
|
||||
* @type {Object<string, FontParameters>}
|
||||
*/
|
||||
const cache = {};
|
||||
return function(fontSpec, callback) {
|
||||
if (!style) {
|
||||
style = document.createElement('div').style;
|
||||
export const getFontParameters = function(fontSpec) {
|
||||
const match = fontSpec.match(fontRegEx);
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
const style = /** @type {FontParameters} */ ({
|
||||
lineHeight: 'normal',
|
||||
size: '1.2em',
|
||||
style: 'normal',
|
||||
weight: 'normal',
|
||||
variant: 'normal'
|
||||
});
|
||||
for (let i = 0, ii = fontRegExMatchIndex.length; i < ii; ++i) {
|
||||
const value = match[i + 1];
|
||||
if (value !== undefined) {
|
||||
style[fontRegExMatchIndex[i]] = value;
|
||||
}
|
||||
if (!(fontSpec in cache)) {
|
||||
style.font = fontSpec;
|
||||
const family = style.fontFamily;
|
||||
if (!family) {
|
||||
callback(null);
|
||||
}
|
||||
const families = family.split(/,\s?/);
|
||||
cache[fontSpec] = {
|
||||
families: families,
|
||||
weight: style.fontWeight,
|
||||
style: style.fontStyle,
|
||||
lineHeight: style.lineHeight
|
||||
};
|
||||
style.font = '';
|
||||
}
|
||||
callback(cache[fontSpec]);
|
||||
};
|
||||
})();
|
||||
}
|
||||
style.families = style.family.split(/,\s?/);
|
||||
return style;
|
||||
};
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import {WORKER_OFFSCREEN_CANVAS} from './has.js';
|
||||
|
||||
/**
|
||||
* @module ol/dom
|
||||
*/
|
||||
@@ -14,9 +16,9 @@
|
||||
export function createCanvasContext2D(opt_width, opt_height, opt_canvasPool) {
|
||||
const canvas = opt_canvasPool && opt_canvasPool.length ?
|
||||
opt_canvasPool.shift() :
|
||||
'document' in self ?
|
||||
document.createElement('canvas') :
|
||||
new OffscreenCanvas(opt_width || 300, opt_height || 300);
|
||||
WORKER_OFFSCREEN_CANVAS ?
|
||||
new OffscreenCanvas(opt_width || 300, opt_height || 300) :
|
||||
document.createElement('canvas');
|
||||
if (opt_width) {
|
||||
canvas.width = opt_width;
|
||||
}
|
||||
|
||||
@@ -37,27 +37,15 @@ export const MAC = ua.indexOf('macintosh') !== -1;
|
||||
* @type {number}
|
||||
* @api
|
||||
*/
|
||||
export const DEVICE_PIXEL_RATIO = (function() {
|
||||
try {
|
||||
return self.devicePixelRatio;
|
||||
} catch (e) {
|
||||
return window.devicePixelRatio || 1;
|
||||
}
|
||||
})();
|
||||
export const DEVICE_PIXEL_RATIO = (typeof self !== 'undefined' ? self.devicePixelRatio : window.devicePixelRatio) || 1;
|
||||
|
||||
/**
|
||||
* The execution context is a window.
|
||||
* The execution context is a worker with OffscreenCanvas available.
|
||||
* @const
|
||||
* @type {boolean}
|
||||
*/
|
||||
export const WINDOW = (function() {
|
||||
try {
|
||||
return 'document' in self;
|
||||
} catch (e) {
|
||||
// ancient browsers don't have `self`
|
||||
return true;
|
||||
}
|
||||
})();
|
||||
export const WORKER_OFFSCREEN_CANVAS = typeof WorkerGlobalScope !== 'undefined' && typeof OffscreenCanvas !== 'undefined' &&
|
||||
self instanceof WorkerGlobalScope; //eslint-disable-line
|
||||
|
||||
/**
|
||||
* Image.prototype.decode() is supported.
|
||||
|
||||
@@ -6,7 +6,7 @@ import {createCanvasContext2D} from '../dom.js';
|
||||
import {clear} from '../obj.js';
|
||||
import BaseObject from '../Object.js';
|
||||
import EventTarget from '../events/Target.js';
|
||||
import {WINDOW} from '../has.js';
|
||||
import {WORKER_OFFSCREEN_CANVAS} from '../has.js';
|
||||
import {toString} from '../transform.js';
|
||||
|
||||
|
||||
@@ -266,7 +266,8 @@ export const registerFont = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
function fontCallback(font) {
|
||||
return function(fontSpec) {
|
||||
const font = getFontParameters(fontSpec);
|
||||
if (!font) {
|
||||
return;
|
||||
}
|
||||
@@ -284,31 +285,6 @@ export const registerFont = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return function(fontSpec) {
|
||||
if (WINDOW) {
|
||||
getFontParameters(fontSpec, fontCallback);
|
||||
} else if (self.postMessage) {
|
||||
/** @type {any} */
|
||||
const worker = self;
|
||||
worker.postMessage({
|
||||
action: 'getFontParameters',
|
||||
font: fontSpec
|
||||
});
|
||||
worker.addEventListener('message', function handler(event) {
|
||||
if (event.data.action === 'getFontParameters') {
|
||||
worker.removeEventListener('message', handler);
|
||||
const font = event.data.font;
|
||||
fontCallback(font);
|
||||
if (!textHeights[fontSpec]) {
|
||||
const metrics = measureText(fontSpec, 'Žg');
|
||||
const lineHeight = isNaN(font.lineHeight) ? 1.2 : Number(font.lineHeight);
|
||||
textHeights[fontSpec] = lineHeight * (metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -323,22 +299,29 @@ export const measureTextHeight = (function() {
|
||||
*/
|
||||
let div;
|
||||
const heights = textHeights;
|
||||
return function(font) {
|
||||
let height = heights[font];
|
||||
return function(fontSpec) {
|
||||
let height = heights[fontSpec];
|
||||
if (height == undefined) {
|
||||
if (!div) {
|
||||
div = document.createElement('div');
|
||||
div.innerHTML = 'M';
|
||||
div.style.margin = '0 !important';
|
||||
div.style.padding = '0 !important';
|
||||
div.style.position = 'absolute !important';
|
||||
div.style.left = '-99999px !important';
|
||||
if (WORKER_OFFSCREEN_CANVAS) {
|
||||
const font = getFontParameters(fontSpec);
|
||||
const metrics = measureText(fontSpec, 'Žg');
|
||||
const lineHeight = isNaN(Number(font.lineHeight)) ? 1.2 : Number(font.lineHeight);
|
||||
textHeights[fontSpec] = lineHeight * (metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent);
|
||||
} else {
|
||||
if (!div) {
|
||||
div = document.createElement('div');
|
||||
div.innerHTML = 'M';
|
||||
div.style.margin = '0 !important';
|
||||
div.style.padding = '0 !important';
|
||||
div.style.position = 'absolute !important';
|
||||
div.style.left = '-99999px !important';
|
||||
}
|
||||
div.style.font = fontSpec;
|
||||
document.body.appendChild(div);
|
||||
height = div.offsetHeight;
|
||||
heights[fontSpec] = height;
|
||||
document.body.removeChild(div);
|
||||
}
|
||||
div.style.font = font;
|
||||
document.body.appendChild(div);
|
||||
height = div.offsetHeight;
|
||||
heights[font] = height;
|
||||
document.body.removeChild(div);
|
||||
}
|
||||
return height;
|
||||
};
|
||||
@@ -369,7 +352,6 @@ export function measureTextWidth(font, text) {
|
||||
return measureText(font, text).width;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Measure text width using a cache.
|
||||
* @param {string} font The font.
|
||||
@@ -484,13 +466,13 @@ let createTransformStringCanvas = null;
|
||||
* @return {string} CSS transform.
|
||||
*/
|
||||
export function createTransformString(transform) {
|
||||
if (WINDOW) {
|
||||
if (WORKER_OFFSCREEN_CANVAS) {
|
||||
return toString(transform);
|
||||
} else {
|
||||
if (!createTransformStringCanvas) {
|
||||
createTransformStringCanvas = createCanvasContext2D(1, 1).canvas;
|
||||
}
|
||||
createTransformStringCanvas.style.transform = toString(transform);
|
||||
return createTransformStringCanvas.style.transform;
|
||||
} else {
|
||||
return toString(transform);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
} from '../../transform.js';
|
||||
import {defaultTextAlign, measureTextHeight, measureAndCacheTextWidth, measureTextWidths} from '../canvas.js';
|
||||
import RBush from 'rbush/rbush.js';
|
||||
import {WINDOW} from '../../has.js';
|
||||
import {WORKER_OFFSCREEN_CANVAS} from '../../has.js';
|
||||
|
||||
|
||||
/**
|
||||
@@ -206,7 +206,7 @@ class Executor {
|
||||
contextInstructions.push('lineJoin', strokeState.lineJoin);
|
||||
contextInstructions.push('miterLimit', strokeState.miterLimit);
|
||||
// eslint-disable-next-line
|
||||
const Context = WINDOW ? CanvasRenderingContext2D : OffscreenCanvasRenderingContext2D;
|
||||
const Context = WORKER_OFFSCREEN_CANVAS ? OffscreenCanvasRenderingContext2D : CanvasRenderingContext2D;
|
||||
if (Context.prototype.setLineDash) {
|
||||
contextInstructions.push('setLineDash', [strokeState.lineDash]);
|
||||
contextInstructions.push('lineDashOffset', strokeState.lineDashOffset);
|
||||
|
||||
Reference in New Issue
Block a user