void TilesManager::discardTexturesVector(unsigned long long sparedDrawCount, WTF::Vector<TileTexture*>& textures, bool deallocateGLTextures) { const unsigned int max = textures.size(); int dealloc = 0; WTF::Vector<int> discardedIndex; for (unsigned int i = 0; i < max; i++) { TextureOwner* owner = textures[i]->owner(); if (!owner || owner->drawCount() < sparedDrawCount) { if (deallocateGLTextures) { // deallocate textures' gl memory textures[i]->discardGLTexture(); discardedIndex.append(i); } else if (owner) { // simply detach textures from owner static_cast<Tile*>(owner)->discardTextures(); } dealloc++; } } bool base = textures == m_textures; // Clean up the vector of TileTextures and reset the max texture count. if (discardedIndex.size()) { android::Mutex::Autolock lock(m_texturesLock); for (int i = discardedIndex.size() - 1; i >= 0; i--) textures.remove(discardedIndex[i]); int remainedTextureNumber = textures.size(); int* countPtr = base ? &m_currentTextureCount : &m_currentLayerTextureCount; if (remainedTextureNumber < *countPtr) { ALOGV("reset currentTextureCount for %s tiles from %d to %d", base ? "base" : "layer", *countPtr, remainedTextureNumber); *countPtr = remainedTextureNumber; } } ALOGV("Discarded %d %s textures (out of %d %s tiles)", dealloc, (deallocateGLTextures ? "gl" : ""), max, base ? "base" : "layer"); }
static void WebHistoryClose(JNIEnv* env, jobject obj, jint frame) { LOG_ASSERT(frame, "Close needs a valid Frame pointer!"); WebCore::Frame* pFrame = (WebCore::Frame*)frame; WebCore::BackForwardList* list = pFrame->page()->backForwardList(); RefPtr<WebCore::HistoryItem> current = list->currentItem(); // Remove each item instead of using close(). close() is intended to be used // right before the list is deleted. WebCore::HistoryItemVector& entries = list->entries(); int size = entries.size(); for (int i = size - 1; i >= 0; --i) list->removeItem(entries[i].get()); // Add the current item back to the list. if (current) { current->setBridge(0); // addItem will update the children to match the newly created bridge list->addItem(current); /* * The Grand Prix site uses anchor navigations to change the display. * WebKit tries to be smart and not load child frames that have the * same history urls during an anchor navigation. This means that the * current history item stored in the child frame's loader does not * match the item found in the history tree. If we remove all the * entries in the back/foward list, we have to restore the entire tree * or else a HistoryItem might have a deleted parent. * * In order to restore the history tree correctly, we have to look up * all the frames first and then look up the history item. We do this * because the history item in the tree may be null at this point. * Unfortunately, a HistoryItem can only search its immediately * children so we do a breadth-first rebuild of the tree. */ // Keep a small list of child frames to traverse. WTF::Vector<WebCore::Frame*> frameQueue; // Fix the top-level item. pFrame->loader()->history()->setCurrentItem(current.get()); WebCore::Frame* child = pFrame->tree()->firstChild(); // Remember the parent history item so we can search for a child item. RefPtr<WebCore::HistoryItem> parent = current; while (child) { // Use the old history item since the current one may have a // deleted parent. WebCore::HistoryItem* item = parent->childItemWithTarget(child->tree()->name()); child->loader()->history()->setCurrentItem(item); // Append the first child to the queue if it exists. If there is no // item, then we do not need to traverse the children since there // will be no parent history item. WebCore::Frame* firstChild; if (item && (firstChild = child->tree()->firstChild())) frameQueue.append(firstChild); child = child->tree()->nextSibling(); // If we don't have a sibling for this frame and the queue isn't // empty, use the next entry in the queue. if (!child && !frameQueue.isEmpty()) { child = frameQueue.at(0); frameQueue.remove(0); // Figure out the parent history item used when searching for // the history item to use. parent = child->tree()->parent()->loader()->history()->currentItem(); } } } }
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; }