BaseTileTexture* TilesManager::getAvailableTexture(BaseTile* owner)
{
    android::Mutex::Autolock lock(m_texturesLock);

    // Sanity check that the tile does not already own a texture
    if (owner->backTexture() && owner->backTexture()->owner() == owner) {
        XLOG("same owner (%d, %d), getAvailableBackTexture(%x) => texture %x",
             owner->x(), owner->y(), owner, owner->backTexture());
        if (owner->isLayerTile())
            m_availableTilesTextures.remove(m_availableTilesTextures.find(owner->backTexture()));
        else
            m_availableTextures.remove(m_availableTextures.find(owner->backTexture()));
        return owner->backTexture();
    }

    WTF::Vector<BaseTileTexture*>* availableTexturePool;
    if (owner->isLayerTile()) {
        availableTexturePool = &m_availableTilesTextures;
    } else {
        availableTexturePool = &m_availableTextures;
    }

    // The heuristic for selecting a texture is as follows:
    //  1. Skip textures currently being painted, they can't be painted while
    //         busy anyway
    //  2. If a tile isn't owned, break with that one
    //  3. Don't let tiles acquire their front textures
    //  4. If we find a tile in the same page with a different scale,
    //         it's old and not visible. Break with that one
    //  5. Otherwise, use the least recently prepared tile, but ignoring tiles
    //         drawn in the last frame to avoid flickering

    BaseTileTexture* farthestTexture = 0;
    unsigned long long oldestDrawCount = getDrawGLCount() - 1;
    const unsigned int max = availableTexturePool->size();
    for (unsigned int i = 0; i < max; i++) {
        BaseTileTexture* texture = (*availableTexturePool)[i];
        BaseTile* currentOwner = static_cast<BaseTile*>(texture->owner());

        if (texture->busy()) {
            // don't bother, since the acquire() will likely fail
            continue;
        }

        if (!currentOwner) {
            // unused texture! take it!
            farthestTexture = texture;
            break;
        }

        if (currentOwner == owner) {
            // Don't let a tile acquire its own front texture, as the
            // acquisition logic doesn't handle that
            continue;
        }

        if (currentOwner->painter() == owner->painter() && texture->scale() != owner->scale()) {
            // if we render the back page with one scale, then another while
            // still zooming, we recycle the tiles with the old scale instead of
            // taking ones from the front page
            farthestTexture = texture;
            break;
        }

        unsigned long long textureDrawCount = currentOwner->drawCount();
        if (oldestDrawCount > textureDrawCount) {
            farthestTexture = texture;
            oldestDrawCount = textureDrawCount;
        }
    }

    if (farthestTexture) {
        BaseTile* previousOwner = static_cast<BaseTile*>(farthestTexture->owner());
        if (farthestTexture->acquire(owner)) {
            if (previousOwner) {
                previousOwner->removeTexture(farthestTexture);

                XLOG("%s texture %p stolen from tile %d, %d for %d, %d, drawCount was %llu (now %llu)",
                     owner->isLayerTile() ? "LAYER" : "BASE",
                     farthestTexture, previousOwner->x(), previousOwner->y(),
                     owner->x(), owner->y(),
                     oldestDrawCount, getDrawGLCount());
            }

            availableTexturePool->remove(availableTexturePool->find(farthestTexture));
            return farthestTexture;
        }
    } else {
        if (owner->isLayerTile()) {
            // couldn't find a tile for a layer, layers shouldn't request redraw
            // TODO: once we do layer prefetching, don't set this for those
            // tiles
            m_layerTexturesRemain = false;
        }
    }

    XLOG("Couldn't find an available texture for %s tile %x (%d, %d) out of %d available",
          owner->isLayerTile() ? "LAYER" : "BASE",
          owner, owner->x(), owner->y(), max);
#ifdef DEBUG
    printTextures();
#endif // DEBUG
    return 0;
}
TileTexture* TilesManager::getAvailableTexture(Tile* owner)
{
    android::Mutex::Autolock lock(m_texturesLock);

    WTF::Vector<TileTexture*>* availableTexturePool;
    if (owner->isLayerTile())
        availableTexturePool = &m_availableTilesTextures;
    else
        availableTexturePool = &m_availableTextures;

    // Sanity check that the tile does not already own a texture
    if (owner->backTexture() && owner->backTexture()->owner() == owner) {
        int removeIndex = availableTexturePool->find(owner->backTexture());

        // TODO: investigate why texture isn't found
        if (removeIndex >= 0)
            availableTexturePool->remove(removeIndex);
        return owner->backTexture();
    }

    // The heuristic for selecting a texture is as follows:
    //  1. Skip textures currently being painted, they can't be painted while
    //         busy anyway
    //  2. If a tile isn't owned, break with that one
    //  3. Don't let tiles acquire their front textures
    //  4. Otherwise, use the least recently prepared tile, but ignoring tiles
    //         drawn in the last frame to avoid flickering

    TileTexture* farthestTexture = 0;
    unsigned long long oldestDrawCount = getDrawGLCount() - 1;
    const unsigned int max = availableTexturePool->size();
    for (unsigned int i = 0; i < max; i++) {
        TileTexture* texture = (*availableTexturePool)[i];
        Tile* currentOwner = static_cast<Tile*>(texture->owner());
        if (!currentOwner) {
            // unused texture! take it!
            farthestTexture = texture;
            break;
        }

        if (currentOwner == owner) {
            // Don't let a tile acquire its own front texture, as the
            // acquisition logic doesn't handle that
            continue;
        }

        unsigned long long textureDrawCount = currentOwner->drawCount();
        if (oldestDrawCount > textureDrawCount) {
            farthestTexture = texture;
            oldestDrawCount = textureDrawCount;
        }
    }

    if (farthestTexture) {
        Tile* previousOwner = static_cast<Tile*>(farthestTexture->owner());
        if (farthestTexture->acquire(owner)) {
            if (previousOwner) {
                previousOwner->removeTexture(farthestTexture);

                ALOGV("%s texture %p stolen from tile %d, %d for %d, %d, drawCount was %llu (now %llu)",
                      owner->isLayerTile() ? "LAYER" : "BASE",
                      farthestTexture, previousOwner->x(), previousOwner->y(),
                      owner->x(), owner->y(),
                      oldestDrawCount, getDrawGLCount());
            }

            availableTexturePool->remove(availableTexturePool->find(farthestTexture));
            return farthestTexture;
        }
    } else {
        if (owner->isLayerTile()) {
            // couldn't find a tile for a layer, layers shouldn't request redraw
            // TODO: once we do layer prefetching, don't set this for those
            // tiles
            m_layerTexturesRemain = false;
        }
    }

    ALOGV("Couldn't find an available texture for %s tile %x (%d, %d) out of %d available",
          owner->isLayerTile() ? "LAYER" : "BASE",
          owner, owner->x(), owner->y(), max);
#ifdef DEBUG
    printTextures();
#endif // DEBUG
    return 0;
}