Merge pull request #9705 from ahocevar/vectortile-render-optimizations
Vector tile renderer optimizations and fixes
This commit is contained in:
@@ -6,7 +6,7 @@ import ImageState from './ImageState.js';
|
||||
import {listenOnce, unlistenByKey} from './events.js';
|
||||
import EventType from './events/EventType.js';
|
||||
import {getHeight} from './extent.js';
|
||||
import {SAFARI} from './has.js';
|
||||
import {IMAGE_DECODE} from './has.js';
|
||||
|
||||
|
||||
/**
|
||||
@@ -159,10 +159,7 @@ class ImageWrapper extends ImageBase {
|
||||
export function listenImage(image, loadHandler, errorHandler) {
|
||||
const img = /** @type {HTMLImageElement} */ (image);
|
||||
|
||||
// The decode function is supported by Safari but not when the image is a svg file.
|
||||
// FIXME: remove `!SAFARI` in the test when this bug is fixed upstream.
|
||||
// See: https://bugs.webkit.org/show_bug.cgi?id=198527
|
||||
if (!SAFARI && img.decode) {
|
||||
if (IMAGE_DECODE) {
|
||||
const promise = img.decode();
|
||||
let listening = true;
|
||||
const unlisten = function() {
|
||||
@@ -174,7 +171,13 @@ export function listenImage(image, loadHandler, errorHandler) {
|
||||
}
|
||||
}).catch(function(error) {
|
||||
if (listening) {
|
||||
errorHandler();
|
||||
// FIXME: Unconditionally call errorHandler() when this bug is fixed upstream:
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=198527
|
||||
if (error.name === 'EncodingError' && error.message === 'Invalid image type.') {
|
||||
loadHandler();
|
||||
} else {
|
||||
errorHandler();
|
||||
}
|
||||
}
|
||||
});
|
||||
return unlisten;
|
||||
|
||||
@@ -22,7 +22,7 @@ import {listen, unlistenByKey, unlisten} from './events.js';
|
||||
import EventType from './events/EventType.js';
|
||||
import {createEmpty, clone, createOrUpdateEmpty, equals, getForViewAndSize, isEmpty} from './extent.js';
|
||||
import {TRUE} from './functions.js';
|
||||
import {DEVICE_PIXEL_RATIO} from './has.js';
|
||||
import {DEVICE_PIXEL_RATIO, IMAGE_DECODE} from './has.js';
|
||||
import LayerGroup from './layer/Group.js';
|
||||
import {hasArea} from './size.js';
|
||||
import {DROP} from './structs/PriorityQueue.js';
|
||||
@@ -967,7 +967,7 @@ class PluggableMap extends BaseObject {
|
||||
if (frameState) {
|
||||
const hints = frameState.viewHints;
|
||||
if (hints[ViewHint.ANIMATING] || hints[ViewHint.INTERACTING]) {
|
||||
const lowOnFrameBudget = Date.now() - frameState.time > 8;
|
||||
const lowOnFrameBudget = !IMAGE_DECODE && Date.now() - frameState.time > 8;
|
||||
maxTotalLoading = lowOnFrameBudget ? 0 : 8;
|
||||
maxNewLoads = lowOnFrameBudget ? 0 : 2;
|
||||
}
|
||||
|
||||
@@ -38,3 +38,9 @@ export const MAC = ua.indexOf('macintosh') !== -1;
|
||||
* @api
|
||||
*/
|
||||
export const DEVICE_PIXEL_RATIO = window.devicePixelRatio || 1;
|
||||
|
||||
/**
|
||||
* Image.prototype.decode() is supported.
|
||||
* @type {boolean}
|
||||
*/
|
||||
export const IMAGE_DECODE = typeof Image !== 'undefined' && Image.prototype.decode;
|
||||
|
||||
@@ -7,6 +7,7 @@ import TileState from '../../TileState.js';
|
||||
import {createEmpty, equals, getIntersection, getTopLeft} from '../../extent.js';
|
||||
import CanvasLayerRenderer from './Layer.js';
|
||||
import {apply as applyTransform, compose as composeTransform, makeInverse, toString as transformToString} from '../../transform.js';
|
||||
import {numberSafeCompareFunction} from '../../array.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
@@ -264,15 +265,7 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
||||
this.renderedTiles.length = 0;
|
||||
/** @type {Array<number>} */
|
||||
let zs = Object.keys(tilesToDrawByZ).map(Number);
|
||||
zs.sort(function(a, b) {
|
||||
if (a === z) {
|
||||
return 1;
|
||||
} else if (b === z) {
|
||||
return -1;
|
||||
} else {
|
||||
return a > b ? 1 : a < b ? -1 : 0;
|
||||
}
|
||||
});
|
||||
zs.sort(numberSafeCompareFunction);
|
||||
|
||||
let clips, clipZs, currentClip;
|
||||
if (layerState.opacity === 1 && (!this.containerReused || tileSource.getOpaque(frameState.viewState.projection))) {
|
||||
@@ -311,32 +304,37 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
||||
const h = nextY - y;
|
||||
const transition = z === currentZ;
|
||||
|
||||
if (clips && (!transition || tile.getAlpha(getUid(this), frameState.time) === 1)) {
|
||||
// Clip mask for regions in this tile that already filled by a higher z tile
|
||||
context.save();
|
||||
currentClip = [x, y, x + w, y, x + w, y + h, x, y + h];
|
||||
for (let i = 0, ii = clips.length; i < ii; ++i) {
|
||||
if (z !== currentZ && currentZ < clipZs[i]) {
|
||||
const clip = clips[i];
|
||||
context.beginPath();
|
||||
// counter-clockwise (outer ring) for current tile
|
||||
context.moveTo(currentClip[0], currentClip[1]);
|
||||
context.lineTo(currentClip[2], currentClip[3]);
|
||||
context.lineTo(currentClip[4], currentClip[5]);
|
||||
context.lineTo(currentClip[6], currentClip[7]);
|
||||
// clockwise (inner ring) for higher z tile
|
||||
context.moveTo(clip[6], clip[7]);
|
||||
context.lineTo(clip[4], clip[5]);
|
||||
context.lineTo(clip[2], clip[3]);
|
||||
context.lineTo(clip[0], clip[1]);
|
||||
context.clip();
|
||||
const inTransition = transition && tile.getAlpha(getUid(this), frameState.time) !== 1;
|
||||
if (!inTransition) {
|
||||
if (clips) {
|
||||
// Clip mask for regions in this tile that already filled by a higher z tile
|
||||
context.save();
|
||||
currentClip = [x, y, x + w, y, x + w, y + h, x, y + h];
|
||||
for (let i = 0, ii = clips.length; i < ii; ++i) {
|
||||
if (z !== currentZ && currentZ < clipZs[i]) {
|
||||
const clip = clips[i];
|
||||
context.beginPath();
|
||||
// counter-clockwise (outer ring) for current tile
|
||||
context.moveTo(currentClip[0], currentClip[1]);
|
||||
context.lineTo(currentClip[2], currentClip[3]);
|
||||
context.lineTo(currentClip[4], currentClip[5]);
|
||||
context.lineTo(currentClip[6], currentClip[7]);
|
||||
// clockwise (inner ring) for higher z tile
|
||||
context.moveTo(clip[6], clip[7]);
|
||||
context.lineTo(clip[4], clip[5]);
|
||||
context.lineTo(clip[2], clip[3]);
|
||||
context.lineTo(clip[0], clip[1]);
|
||||
context.clip();
|
||||
}
|
||||
}
|
||||
clips.push(currentClip);
|
||||
clipZs.push(currentZ);
|
||||
} else {
|
||||
context.clearRect(x, y, w, h);
|
||||
}
|
||||
clips.push(currentClip);
|
||||
clipZs.push(currentZ);
|
||||
}
|
||||
this.drawTileImage(tile, frameState, x, y, w, h, tileGutter, transition, layerState.opacity);
|
||||
if (clips) {
|
||||
if (clips && !inTransition) {
|
||||
context.restore();
|
||||
}
|
||||
this.renderedTiles.push(tile);
|
||||
|
||||
Reference in New Issue
Block a user