Example #1
0
/**
 *  Return a random SkIRect inside the range specified.
 *  @param rand Random number generator.
 *  @param maxX Exclusive maximum x-coordinate. SkIRect's fLeft and fRight will be
 *      in the range [0, maxX)
 *  @param maxY Exclusive maximum y-coordinate. SkIRect's fTop and fBottom will be
 *      in the range [0, maxY)
 *  @return SkIRect Non-empty, non-degenerate rectangle.
 */
static SkIRect generate_random_rect(SkRandom* rand, int32_t maxX, int32_t maxY) {
    SkASSERT(maxX > 1 && maxY > 1);
    int32_t left = rand->nextULessThan(maxX);
    int32_t right = rand->nextULessThan(maxX);
    int32_t top = rand->nextULessThan(maxY);
    int32_t bottom = rand->nextULessThan(maxY);
    SkIRect rect = SkIRect::MakeLTRB(left, top, right, bottom);
    rect.sort();
    // Make sure rect is not empty.
    if (rect.fLeft == rect.fRight) {
        if (rect.fLeft > 0) {
            rect.fLeft--;
        } else {
            rect.fRight++;
            // This branch is only taken if 0 == rect.fRight, and
            // maxX must be at least 2, so it must still be in
            // range.
            SkASSERT(rect.fRight < maxX);
        }
    }
    if (rect.fTop == rect.fBottom) {
        if (rect.fTop > 0) {
            rect.fTop--;
        } else {
            rect.fBottom++;
            // Again, this must be in range.
            SkASSERT(rect.fBottom < maxY);
        }
    }
    return rect;
}
Example #2
0
SkIRect generate_random_subset(SkRandom* rand, int w, int h) {
    SkIRect rect;
    do {
        rect.fLeft = rand->nextRangeU(0, w);
        rect.fTop = rand->nextRangeU(0, h);
        rect.fRight = rand->nextRangeU(0, w);
        rect.fBottom = rand->nextRangeU(0, h);
        rect.sort();
    } while (rect.isEmpty());
    return rect;
}
static SkIRect random_rect(SkRandom& rand) {
    SkIRect rect = {0,0,0,0};
    while (rect.isEmpty()) {
        rect.fLeft   = rand.nextS() % MAX_SIZE;
        rect.fRight  = rand.nextS() % MAX_SIZE;
        rect.fTop    = rand.nextS() % MAX_SIZE;
        rect.fBottom = rand.nextS() % MAX_SIZE;
        rect.sort();
    }
    return rect;
}
void SkTileGrid::search(const SkIRect& query, SkTDArray<void*>* results) {
    SkIRect adjustedQuery = query;
    // The inset is to counteract the outset that was applied in 'insert'
    // The outset/inset is to optimize for lookups of size
    // 'tileInterval + 2 * margin' that are aligned with the tile grid.
    adjustedQuery.inset(fInfo.fMargin.width(), fInfo.fMargin.height());
    adjustedQuery.offset(fInfo.fOffset);
    adjustedQuery.sort();  // in case the inset inverted the rectangle
    // Convert the query rectangle from device coordinates to tile coordinates
    // by rounding outwards to the nearest tile boundary so that the resulting tile
    // region includes the query rectangle. (using truncating division to "floor")
    int tileStartX = adjustedQuery.left() / fInfo.fTileInterval.width();
    int tileEndX = (adjustedQuery.right() + fInfo.fTileInterval.width() - 1) /
        fInfo.fTileInterval.width();
    int tileStartY = adjustedQuery.top() / fInfo.fTileInterval.height();
    int tileEndY = (adjustedQuery.bottom() + fInfo.fTileInterval.height() - 1) /
        fInfo.fTileInterval.height();

    tileStartX = SkPin32(tileStartX, 0, fXTileCount - 1);
    tileEndX = SkPin32(tileEndX, tileStartX+1, fXTileCount);
    tileStartY = SkPin32(tileStartY, 0, fYTileCount - 1);
    tileEndY = SkPin32(tileEndY, tileStartY+1, fYTileCount);

    int queryTileCount = (tileEndX - tileStartX) * (tileEndY - tileStartY);
    SkASSERT(queryTileCount);
    if (queryTileCount == 1) {
        *results = this->tile(tileStartX, tileStartY);
    } else {
        results->reset();
        SkTDArray<int> curPositions;
        curPositions.setCount(queryTileCount);
        // Note: Reserving space for 1024 tile pointers on the stack. If the
        // malloc becomes a bottleneck, we may consider increasing that number.
        // Typical large web page, say 2k x 16k, would require 512 tiles of
        // size 256 x 256 pixels.
        SkAutoSTArray<1024, SkTDArray<void *>*> storage(queryTileCount);
        SkTDArray<void *>** tileRange = storage.get();
        int tile = 0;
        for (int x = tileStartX; x < tileEndX; ++x) {
            for (int y = tileStartY; y < tileEndY; ++y) {
                tileRange[tile] = &this->tile(x, y);
                curPositions[tile] = tileRange[tile]->count() ? 0 : kTileFinished;
                ++tile;
            }
        }
        void *nextElement;
        while(NULL != (nextElement = fNextDatumFunction(tileRange, curPositions))) {
            results->push(nextElement);
        }
    }
}
Example #5
0
void SkTileGrid::search(const SkRect& query, SkTDArray<void*>* results) const {
    SkIRect adjusted;
    query.roundOut(&adjusted);

    // The inset is to counteract the outset that was applied in 'insert'
    // The outset/inset is to optimize for lookups of size
    // 'tileInterval + 2 * margin' that are aligned with the tile grid.
    adjusted.inset(fInfo.fMargin.width(), fInfo.fMargin.height());
    adjusted.offset(fInfo.fOffset);
    adjusted.sort();  // in case the inset inverted the rectangle

    // Convert the query rectangle from device coordinates to tile coordinates
    // by rounding outwards to the nearest tile boundary so that the resulting tile
    // region includes the query rectangle.
    int startX = adjusted.left() / fInfo.fTileInterval.width(),
        startY = adjusted.top()  / fInfo.fTileInterval.height();
    int endX = divide_ceil(adjusted.right(),  fInfo.fTileInterval.width()),
        endY = divide_ceil(adjusted.bottom(), fInfo.fTileInterval.height());

    // Logically, we could pin endX to [startX, fXTiles], but we force it
    // up to (startX, fXTiles] to make sure we hit at least one tile.
    // This snaps just-out-of-bounds queries to the neighboring border tile.
    // I don't know if this is an important feature outside of unit tests.
    startX = SkPin32(startX, 0, fXTiles - 1);
    startY = SkPin32(startY, 0, fYTiles - 1);
    endX   = SkPin32(endX, startX + 1, fXTiles);
    endY   = SkPin32(endY, startY + 1, fYTiles);

    const int tilesHit = (endX - startX) * (endY - startY);
    SkASSERT(tilesHit > 0);

    if (tilesHit == 1) {
        // A performance shortcut.  The merging code below would work fine here too.
        const SkTDArray<Entry>& tile = fTiles[startY * fXTiles + startX];
        results->setCount(tile.count());
        for (int i = 0; i < tile.count(); i++) {
            (*results)[i] = tile[i].data;
        }
        return;
    }

    // We've got to merge the data in many tiles into a single sorted and deduplicated stream.
    // We do a simple k-way merge based on the order the data was inserted.

    // Gather pointers to the starts and ends of the tiles to merge.
    SkAutoSTArray<kStackAllocationTileCount, const Entry*> starts(tilesHit), ends(tilesHit);
    int i = 0;
    for (int x = startX; x < endX; x++) {
        for (int y = startY; y < endY; y++) {
            starts[i] = fTiles[y * fXTiles + x].begin();
            ends[i]  = fTiles[y * fXTiles + x].end();
            i++;
        }
    }

    // Merge tiles into results until they're fully consumed.
    results->reset();
    while (true) {
        // The tiles themselves are already ordered, so the earliest is at the front of some tile.
        // It may be at the front of several, even all, tiles.
        const Entry* earliest = NULL;
        for (int i = 0; i < starts.count(); i++) {
            if (starts[i] < ends[i]) {
                if (NULL == earliest || starts[i]->order < earliest->order) {
                    earliest = starts[i];
                }
            }
        }

        // If we didn't find an earliest entry, there isn't anything left to merge.
        if (NULL == earliest) {
            return;
        }

        // We did find an earliest entry. Output it, and step forward every tile that contains it.
        results->push(earliest->data);
        for (int i = 0; i < starts.count(); i++) {
            if (starts[i] < ends[i] && starts[i]->order == earliest->order) {
                starts[i]++;
            }
        }
    }
}