Fix tests: always fetch up-to-date pixel values, prevent adding loaded tile to the 'bestTiles' array. Enforce _needsDraw check to be based on lastDrawn - we are async now.

This commit is contained in:
Aiosa 2024-02-05 09:42:26 +01:00
parent fcf20be8ea
commit 9ef2d46e75
5 changed files with 68 additions and 46 deletions

View File

@ -352,7 +352,8 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
* @returns {Boolean} whether the item still needs to be drawn due to blending
*/
setDrawn: function(){
this._needsDraw = this._isBlending || this._wasBlending;
this._needsDraw = this._isBlending || this._wasBlending ||
(this.opacity > 0 && this._lastDrawn.length < 1);
return this._needsDraw;
},
@ -1825,7 +1826,8 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
if ( tile.loading ) {
// the tile is already in the download queue
this._tilesLoading++;
} else if (!loadingCoverage) {
} else if (!tile.loaded && !loadingCoverage) {
// add tile to best tiles to load only when not loaded already
best = this._compareTiles( best, tile, this.maxTilesPerFrame );
}

View File

@ -87,10 +87,6 @@
this._clippingContext = null;
this._renderingCanvas = null;
// Unique type per drawer: uploads texture to unique webgl context.
this._dataType = `${Date.now()}_TEX_2D`;
this._setupTextureHandlers(this._dataType);
// Reject listening for the tile-drawing and tile-drawn events, which this drawer does not fire
this.viewer.rejectEventHandler("tile-drawn", "The WebGLDrawer does not raise the tile-drawn event");
this.viewer.rejectEventHandler("tile-drawing", "The WebGLDrawer does not raise the tile-drawing event");
@ -101,6 +97,10 @@
this._setupCanvases();
this._setupRenderer();
// Unique type per drawer: uploads texture to unique webgl context.
this._dataType = `${Date.now()}_TEX_2D`;
this._setupTextureHandlers(this._dataType);
this.context = this._outputContext; // API required by tests
}
@ -757,7 +757,6 @@
this._renderingCanvas.height = this._clippingCanvas.height = this._outputCanvas.height;
this._gl = this._renderingCanvas.getContext('webgl');
//make the additional canvas elements mirror size changes to the output canvas
this.viewer.addHandler("resize", function(){
@ -784,12 +783,14 @@
}
_setupTextureHandlers(thisType) {
const _this = this;
const tex2DCompatibleLoader = (tile, data) => {
let tiledImage = tile.tiledImage;
//todo verify we are calling conversion just right amount of time!
// e.g. no upload of cpu-existing texture
// also check textures are really getting destroyed (it is tested, but also do this with demos)
let gl = this._gl;
let gl = _this._gl;
// create a gl Texture for this tile and bind the canvas with the image data
let texture = gl.createTexture();
@ -798,16 +799,16 @@
if( overlap > 0){
// calculate the normalized position of the rect to actually draw
// discarding overlap.
let overlapFraction = this._calculateOverlapFraction(tile, tiledImage);
let overlapFraction = _this._calculateOverlapFraction(tile, tiledImage);
let left = tile.x === 0 ? 0 : overlapFraction.x;
let top = tile.y === 0 ? 0 : overlapFraction.y;
let right = tile.isRightMost ? 1 : 1 - overlapFraction.x;
let bottom = tile.isBottomMost ? 1 : 1 - overlapFraction.y;
position = this._makeQuadVertexBuffer(left, right, top, bottom);
position = _this._makeQuadVertexBuffer(left, right, top, bottom);
} else {
// no overlap: this texture can use the unit quad as its position data
position = this._unitQuad;
position = _this._unitQuad;
}
gl.activeTexture(gl.TEXTURE0);
@ -848,11 +849,12 @@
this.declareSupportedDataFormats(imageTexType, c2dTexType);
// We should be OK uploading any of these types.
$.convertor.learn("context2d", c2dTexType, tex2DCompatibleLoader, 1, 2);
$.convertor.learn("image", imageTexType, tex2DCompatibleLoader, 1, 2);
$.convertor.learn(c2dTexType, "context2d", dataRetrieval, 1, 2);
$.convertor.learn(imageTexType, "image", dataRetrieval, 1, 2);
// We should be OK uploading any of these types. The complexity is selected to be O(3n), should be
// more than linear pass over pixels
$.convertor.learn("context2d", c2dTexType, tex2DCompatibleLoader, 1, 3);
$.convertor.learn("image", imageTexType, tex2DCompatibleLoader, 1, 3);
$.convertor.learn(c2dTexType, "context2d", dataRetrieval, 1, 3);
$.convertor.learn(imageTexType, "image", dataRetrieval, 1, 3);
$.convertor.learnDestroy(c2dTexType, tex2DCompatibleDestructor);
$.convertor.learnDestroy(imageTexType, tex2DCompatibleDestructor);

View File

@ -284,9 +284,9 @@ $.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.W
draw: function() {
this.viewer.drawer.draw(this._items);
this._needsDraw = false;
this._items.forEach(function(item){
for (let item of this._items) {
this._needsDraw = item.setDrawn() || this._needsDraw;
});
}
},
/**

View File

@ -220,17 +220,23 @@
var done = assert.async();
viewer.open('/test/data/testpattern.dzi');
var density = OpenSeadragon.pixelDensityRatio;
function getPixelFromViewerScreenCoords(x, y) {
const density = OpenSeadragon.pixelDensityRatio;
const imageData = viewer.drawer.context.getImageData(x * density, y * density, 1, 1);
return {
r: imageData.data[0],
g: imageData.data[1],
b: imageData.data[2],
a: imageData.data[3]
};
}
viewer.addHandler('open', function() {
var firstImage = viewer.world.getItemAt(0);
firstImage.addHandler('fully-loaded-change', function() {
viewer.addOnceHandler('update-viewport', function(){
var imageData = viewer.drawer.context.getImageData(0, 0,
500 * density, 500 * density);
// Pixel 250,250 will be in the hole of the A
var expectedVal = getPixelValue(imageData, 250 * density, 250 * density);
var expectedVal = getPixelFromViewerScreenCoords(250, 250);
assert.notEqual(expectedVal.r, 0, 'Red channel should not be 0');
assert.notEqual(expectedVal.g, 0, 'Green channel should not be 0');
@ -242,9 +248,8 @@
success: function() {
var secondImage = viewer.world.getItemAt(1);
secondImage.addHandler('fully-loaded-change', function() {
viewer.addOnceHandler('update-viewport',function(){
var imageData = viewer.drawer.context.getImageData(0, 0, 500 * density, 500 * density);
var actualVal = getPixelValue(imageData, 250 * density, 250 * density);
viewer.addOnceHandler('update-viewport', function(){
var actualVal = getPixelFromViewerScreenCoords(250, 250);
assert.equal(actualVal.r, expectedVal.r,
'Red channel should not change in transparent part of the A');
@ -255,10 +260,10 @@
assert.equal(actualVal.a, expectedVal.a,
'Alpha channel should not change in transparent part of the A');
var onAVal = getPixelValue(imageData, 333 * density, 250 * density);
assert.equal(onAVal.r, 0, 'Red channel should be null on the A');
assert.equal(onAVal.g, 0, 'Green channel should be null on the A');
assert.equal(onAVal.b, 0, 'Blue channel should be null on the A');
var onAVal = getPixelFromViewerScreenCoords(333 , 250);
assert.equal(onAVal.r, 0, 'Red channel should be 0 on the A');
assert.equal(onAVal.g, 0, 'Green channel should be 0 on the A');
assert.equal(onAVal.b, 0, 'Blue channel should be 0 on the A');
assert.equal(onAVal.a, 255, 'Alpha channel should be 255 on the A');
done();
@ -271,17 +276,6 @@
});
});
});
function getPixelValue(imageData, x, y) {
var offset = 4 * (y * imageData.width + x);
return {
r: imageData.data[offset],
g: imageData.data[offset + 1],
b: imageData.data[offset + 2],
a: imageData.data[offset + 3]
};
}
});
}
})();

View File

@ -123,7 +123,13 @@
QUnit.test('basics', function(assert) {
const done = assert.async();
const fakeViewer = {
raiseEvent: function() {}
raiseEvent: function() {},
drawer: {
// tile in safe mode inspects the supported formats upon cache set
getSupportedDataFormats() {
return [T_A, T_B, T_C, T_D, T_E];
}
}
};
const fakeTiledImage0 = {
viewer: fakeViewer,
@ -170,7 +176,13 @@
QUnit.test('maxImageCacheCount', function(assert) {
const done = assert.async();
const fakeViewer = {
raiseEvent: function() {}
raiseEvent: function() {},
drawer: {
// tile in safe mode inspects the supported formats upon cache set
getSupportedDataFormats() {
return [T_A, T_B, T_C, T_D, T_E];
}
}
};
const fakeTiledImage0 = {
viewer: fakeViewer,
@ -218,7 +230,13 @@
QUnit.test('Tile API: basic conversion', function(test) {
const done = test.async();
const fakeViewer = {
raiseEvent: function() {}
raiseEvent: function() {},
drawer: {
// tile in safe mode inspects the supported formats upon cache set
getSupportedDataFormats() {
return [T_A, T_B, T_C, T_D, T_E];
}
}
};
const tileCache = new OpenSeadragon.TileCache();
const fakeTiledImage0 = {
@ -406,7 +424,13 @@
QUnit.test('Tile API Cache Interaction', function(test) {
const done = test.async();
const fakeViewer = {
raiseEvent: function() {}
raiseEvent: function() {},
drawer: {
// tile in safe mode inspects the supported formats upon cache set
getSupportedDataFormats() {
return [T_A, T_B, T_C, T_D, T_E];
}
}
};
const tileCache = new OpenSeadragon.TileCache();
const fakeTiledImage0 = {