This is an automated email from the ASF dual-hosted git repository. desruisseaux pushed a commit to branch geoapi-4.0 in repository https://gitbox.apache.org/repos/asf/sis.git
commit f87196f3bd75e44a9df100e435e25b24dc892d7c Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Mon Nov 8 17:03:52 2021 +0100 Fix `IndexOutOfBoundsException` when filling a tile having an origin other than (0,0). Fix the conditions for deciding when to return an empty tile or the existing tile. --- .../java/org/apache/sis/image/MaskedImage.java | 34 +++++++++++++++------- .../sis/internal/coverage/j2d/FillValues.java | 4 +-- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/MaskedImage.java b/core/sis-feature/src/main/java/org/apache/sis/image/MaskedImage.java index 63ec657..9654e14 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/image/MaskedImage.java +++ b/core/sis-feature/src/main/java/org/apache/sis/image/MaskedImage.java @@ -257,10 +257,12 @@ final class MaskedImage extends SourceAlignedImage { */ final Rectangle maskBounds = this.maskBounds; final LongBuffer mask = getMask().asLongBuffer(); + final int xmax = xmin + source.getTileWidth(); + final int ymax = ymin + source.getTileHeight(); + final int xEnd = Math.min(xmax, maskBounds.x + maskBounds.width); + final int yEnd = Math.min(ymax, maskBounds.y + maskBounds.height); final int xStart = Math.max(xmin, maskBounds.x); final int yStart = Math.max(ymin, maskBounds.y); - final int xEnd = Math.min(xmin + source.getTileWidth(), maskBounds.x + maskBounds.width); - final int yEnd = Math.min(ymin + source.getTileHeight(), maskBounds.y + maskBounds.height); final int imax = xEnd - maskBounds.x; // Maximum x index in mask, exclusive. final int xoff = xStart - maskBounds.x; Raster data = null; @@ -367,17 +369,30 @@ final class MaskedImage extends SourceAlignedImage { } /* * The tile is fetched only if at least one pixel needs to be copied from the source tile. - * If the source tile is still null at this point, it means that target tile is fully empty. - * Note that the target tile may be non-null because it was an argument to this method. + * If the source tile is still null at this point, it means that masked region is fully empty. + * Note that the `target` variable may be non-null because it was an argument to this method. */ + final boolean isFullTile = (xStart == xmin && yStart == ymin && xEnd == xmax && yEnd == ymax); if (data == null) { - return createEmptyTile(xmin, ymin); + if (isFullTile) { + return createEmptyTile(xmin, ymin); + } + data = source.getTile(tileX, tileY); + boolean clean = needCreate(tile, data); + if (clean) { + tile = createTile(tileX, tileY); + clean = fillValues.isFullyZero; + } + if (!clean) { + fillValues.fill(tile); + } } /* * If no bit from the `present` mask have been cleared, then it means that all pixels * have been copied. In such case the source tile can be returned directly. */ - if (present == -1) { + assert data.getMinX() == xmin && data.getMinY() == ymin; + if (present == -1 && (isFullTile | maskInside)) { return data; } /* @@ -385,11 +400,8 @@ final class MaskedImage extends SourceAlignedImage { * there is some pixels that we need to copy here. */ if (maskInside) { - final int width = tile.getWidth(); - int height = tile.getHeight(); - final int xmax = xmin + width; - final int ymax = ymin + height; - height -= (yStart - ymin) + (ymax - yEnd); + final int width = xmax - xmin; + final int height = yEnd - yStart; complete: for (int border = 0; ; border++) { final int start, span; switch (border) { diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/FillValues.java b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/FillValues.java index f620ad1..1533717 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/FillValues.java +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/FillValues.java @@ -156,14 +156,14 @@ public final class FillValues { chunk = tile.getDataElements(xmin, y, chunkWidth, 1, null); final int ymax = y + tile.getHeight(); final int xmax = xmin + width; - int x = chunkWidth; + int x = xmin + chunkWidth; do { int remaining; while ((remaining = xmax - x) > 0) { tile.setDataElements(x, y, Math.min(chunkWidth, remaining), 1, chunk); x += chunkWidth; } - x = 0; + x = xmin; } while (++y < ymax); }