diff options
Diffstat (limited to 'Source/WebCore')
44 files changed, 764 insertions, 362 deletions
diff --git a/Source/WebCore/loader/cache/CachedImage.cpp b/Source/WebCore/loader/cache/CachedImage.cpp index ba30860..6867302 100644 --- a/Source/WebCore/loader/cache/CachedImage.cpp +++ b/Source/WebCore/loader/cache/CachedImage.cpp @@ -57,6 +57,7 @@ CachedImage::CachedImage(const String& url) , m_image(0) , m_decodedDataDeletionTimer(this, &CachedImage::decodedDataDeletionTimerFired) , m_shouldPaintBrokenImage(true) + , m_autoLoadWasPreventedBySettings(false) { setStatus(Unknown); } @@ -66,6 +67,7 @@ CachedImage::CachedImage(Image* image) , m_image(image) , m_decodedDataDeletionTimer(this, &CachedImage::decodedDataDeletionTimerFired) , m_shouldPaintBrokenImage(true) + , m_autoLoadWasPreventedBySettings(false) { setStatus(Cached); setLoading(false); diff --git a/Source/WebCore/loader/cache/CachedImage.h b/Source/WebCore/loader/cache/CachedImage.h index 42c7814..79643d7 100644 --- a/Source/WebCore/loader/cache/CachedImage.h +++ b/Source/WebCore/loader/cache/CachedImage.h @@ -75,7 +75,7 @@ public: void clear(); - bool stillNeedsLoad() const { return !errorOccurred() && status() == Unknown && !isLoading(); } + bool stillNeedsLoad() const { return (!errorOccurred() && status() == Unknown && !isLoading()) || (m_autoLoadWasPreventedBySettings && !inCache()); } void load(); // ImageObserver @@ -86,6 +86,8 @@ public: virtual void animationAdvanced(const Image*); virtual void changedInRect(const Image*, const IntRect&); + void setAutoLoadWasPreventedBySettings(bool prevented) { m_autoLoadWasPreventedBySettings = prevented; } + private: void createImage(); size_t maximumDecodedImageSize(); @@ -98,6 +100,7 @@ private: RefPtr<Image> m_image; Timer<CachedImage> m_decodedDataDeletionTimer; bool m_shouldPaintBrokenImage; + bool m_autoLoadWasPreventedBySettings; }; } diff --git a/Source/WebCore/loader/cache/CachedResource.cpp b/Source/WebCore/loader/cache/CachedResource.cpp index 95f5522..e599769 100644 --- a/Source/WebCore/loader/cache/CachedResource.cpp +++ b/Source/WebCore/loader/cache/CachedResource.cpp @@ -261,7 +261,7 @@ void CachedResource::addClient(CachedResourceClient* client) void CachedResource::didAddClient(CachedResourceClient* c) { - if (!isLoading()) + if (!isLoading() && !stillNeedsLoad()) c->notifyFinished(this); } diff --git a/Source/WebCore/loader/cache/CachedResource.h b/Source/WebCore/loader/cache/CachedResource.h index 72b00e5..2f33ac7 100644 --- a/Source/WebCore/loader/cache/CachedResource.h +++ b/Source/WebCore/loader/cache/CachedResource.h @@ -127,6 +127,7 @@ public: bool isLoading() const { return m_loading; } void setLoading(bool b) { m_loading = b; } + virtual bool stillNeedsLoad() const { return false; } virtual bool isImage() const { return false; } bool isLinkResource() const diff --git a/Source/WebCore/loader/cache/CachedResourceLoader.cpp b/Source/WebCore/loader/cache/CachedResourceLoader.cpp index 38fcee4..91c0629 100644 --- a/Source/WebCore/loader/cache/CachedResourceLoader.cpp +++ b/Source/WebCore/loader/cache/CachedResourceLoader.cpp @@ -138,14 +138,21 @@ CachedImage* CachedResourceLoader::requestImage(const String& url) } } CachedImage* resource = static_cast<CachedImage*>(requestResource(CachedResource::ImageResource, url, String())); - if (autoLoadImages() && resource && resource->stillNeedsLoad()) { + if (resource) { #ifdef ANDROID_BLOCK_NETWORK_IMAGE - if (shouldBlockNetworkImage(url)) { - return resource; - } + resource->setAutoLoadWasPreventedBySettings(!autoLoadImages() || shouldBlockNetworkImage(url)); +#else + resource->setAutoLoadWasPreventedBySettings(!autoLoadImages()); +#endif + if (autoLoadImages() && resource->stillNeedsLoad()) { +#ifdef ANDROID_BLOCK_NETWORK_IMAGE + if (shouldBlockNetworkImage(url)) { + return resource; + } #endif - resource->setLoading(true); - load(resource, true); + resource->setLoading(true); + load(resource, true); + } } return resource; } @@ -520,9 +527,12 @@ void CachedResourceLoader::setAutoLoadImages(bool enable) if (shouldBlockNetworkImage(image->url())) continue; #endif + image->setAutoLoadWasPreventedBySettings(false); - if (image->stillNeedsLoad()) + if (image->stillNeedsLoad()) { + image->setLoading(true); load(image, true); + } } } } @@ -536,7 +546,6 @@ bool CachedResourceLoader::shouldBlockNetworkImage(const String& url) const KURL kurl = m_document->completeURL(url); if (kurl.protocolIs("http") || kurl.protocolIs("https")) return true; - return false; } @@ -555,8 +564,11 @@ void CachedResourceLoader::setBlockNetworkImage(bool block) CachedResource* resource = it->second.get(); if (resource->type() == CachedResource::ImageResource) { CachedImage* image = const_cast<CachedImage*>(static_cast<const CachedImage*>(resource)); - if (image->stillNeedsLoad()) + image->setAutoLoadWasPreventedBySettings(false); + if (image->stillNeedsLoad()) { + image->setLoading(true); load(image, true); + } } } } diff --git a/Source/WebCore/platform/graphics/android/AndroidAnimation.cpp b/Source/WebCore/platform/graphics/android/AndroidAnimation.cpp index 5601269..6b22359 100644 --- a/Source/WebCore/platform/graphics/android/AndroidAnimation.cpp +++ b/Source/WebCore/platform/graphics/android/AndroidAnimation.cpp @@ -49,6 +49,8 @@ namespace WebCore { +static int gUniqueId; + static long gDebugAndroidAnimationInstances; long AndroidAnimation::instancesCount() @@ -69,27 +71,11 @@ AndroidAnimation::AndroidAnimation(AnimatedPropertyID type, , m_timingFunction(animation->timingFunction()) , m_type(type) , m_operations(operations) + , m_uniqueId(++gUniqueId) + , m_hasFinished(false) { ASSERT(m_timingFunction); - if (!static_cast<int>(beginTime)) // time not set - m_beginTime = WTF::currentTime(); - - gDebugAndroidAnimationInstances++; -} - -AndroidAnimation::AndroidAnimation(AndroidAnimation* anim) - : m_beginTime(anim->m_beginTime) - , m_duration(anim->m_duration) - , m_fillsBackwards(anim->m_fillsBackwards) - , m_fillsForwards(anim->m_fillsForwards) - , m_iterationCount(anim->m_iterationCount) - , m_direction(anim->m_direction) - , m_timingFunction(anim->m_timingFunction) - , m_name(anim->name()) - , m_type(anim->m_type) - , m_operations(anim->m_operations) -{ gDebugAndroidAnimationInstances++; } @@ -98,20 +84,23 @@ AndroidAnimation::~AndroidAnimation() gDebugAndroidAnimationInstances--; } -double AndroidAnimation::elapsedTime(double time) +void AndroidAnimation::suggestBeginTime(double time) { - if (m_beginTime <= 0.000001) // overflow or not correctly set + if (m_beginTime <= 0.000001) // overflow or not yet set m_beginTime = time; +} - m_elapsedTime = time - m_beginTime; +double AndroidAnimation::elapsedTime(double time) +{ + double elapsedTime = (m_beginTime < 0.000001) ? 0 : time - m_beginTime; if (m_duration <= 0) m_duration = 0.000001; - if (m_elapsedTime < 0) // animation not yet started. + if (elapsedTime < 0) // animation not yet started. return 0; - return m_elapsedTime; + return elapsedTime; } bool AndroidAnimation::checkIterationsAndProgress(double time, float* finalProgress) @@ -127,6 +116,13 @@ bool AndroidAnimation::checkIterationsAndProgress(double time, float* finalProgr // If not infinite, return false if we are done if (m_iterationCount > 0 && progress > dur) { *finalProgress = 1.0; + if (!m_hasFinished) { + // first time past duration, continue with progress 1.0 so the + // element's final position lines up with it's last keyframe + m_hasFinished = true; + return true; + } + return false; } @@ -187,7 +183,7 @@ bool AndroidAnimation::evaluate(LayerAndroid* layer, double time) if (progress < 0) { // The animation hasn't started yet - if (m_fillsBackwards) { + if (m_fillsBackwards || m_beginTime <= 0.000001) { // in this case we want to apply the initial keyframe to the layer applyForProgress(layer, 0); } @@ -195,7 +191,7 @@ bool AndroidAnimation::evaluate(LayerAndroid* layer, double time) return true; } - if (progress >= 1) { + if (progress > 1) { if (!m_fillsForwards) return false; progress = 1; @@ -225,16 +221,6 @@ AndroidOpacityAnimation::AndroidOpacityAnimation(const Animation* animation, { } -AndroidOpacityAnimation::AndroidOpacityAnimation(AndroidOpacityAnimation* anim) - : AndroidAnimation(anim) -{ -} - -PassRefPtr<AndroidAnimation> AndroidOpacityAnimation::copy() -{ - return adoptRef(new AndroidOpacityAnimation(this)); -} - void AndroidAnimation::pickValues(double progress, int* start, int* end) { float distance = -1; @@ -298,16 +284,6 @@ AndroidTransformAnimation::AndroidTransformAnimation(const Animation* animation, { } -AndroidTransformAnimation::AndroidTransformAnimation(AndroidTransformAnimation* anim) - : AndroidAnimation(anim) -{ -} - -PassRefPtr<AndroidAnimation> AndroidTransformAnimation::copy() -{ - return adoptRef(new AndroidTransformAnimation(this)); -} - void AndroidTransformAnimation::applyForProgress(LayerAndroid* layer, float progress) { // First, we need to get the from and to values diff --git a/Source/WebCore/platform/graphics/android/AndroidAnimation.h b/Source/WebCore/platform/graphics/android/AndroidAnimation.h index 16a63e8..dca769f 100644 --- a/Source/WebCore/platform/graphics/android/AndroidAnimation.h +++ b/Source/WebCore/platform/graphics/android/AndroidAnimation.h @@ -33,16 +33,15 @@ namespace WebCore { class TimingFunction; -class AndroidAnimation : public RefCounted<AndroidAnimation> { +class AndroidAnimation : public ThreadSafeRefCounted<AndroidAnimation> { public: AndroidAnimation(AnimatedPropertyID type, const Animation* animation, KeyframeValueList* operations, double beginTime); - AndroidAnimation(AndroidAnimation* anim); virtual ~AndroidAnimation(); - virtual PassRefPtr<AndroidAnimation> copy() = 0; + void suggestBeginTime(double time); double elapsedTime(double time); void pickValues(double progress, int* start, int* end); bool checkIterationsAndProgress(double time, float* finalProgress); @@ -56,11 +55,10 @@ public: AnimatedPropertyID type() { return m_type; } bool fillsBackwards() { return m_fillsBackwards; } bool fillsForwards() { return m_fillsForwards; } - + int uniqueId() { return m_uniqueId; } protected: double m_beginTime; - double m_elapsedTime; double m_duration; bool m_fillsBackwards; bool m_fillsForwards; @@ -70,6 +68,8 @@ protected: String m_name; AnimatedPropertyID m_type; KeyframeValueList* m_operations; + int m_uniqueId; + bool m_hasFinished; }; class AndroidOpacityAnimation : public AndroidAnimation { @@ -80,8 +80,6 @@ public: AndroidOpacityAnimation(const Animation* animation, KeyframeValueList* operations, double beginTime); - AndroidOpacityAnimation(AndroidOpacityAnimation* anim); - virtual PassRefPtr<AndroidAnimation> copy(); virtual void applyForProgress(LayerAndroid* layer, float progress); }; @@ -96,9 +94,6 @@ public: KeyframeValueList* operations, double beginTime); - AndroidTransformAnimation(AndroidTransformAnimation* anim); - virtual PassRefPtr<AndroidAnimation> copy(); - virtual void applyForProgress(LayerAndroid* layer, float progress); }; diff --git a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp index 8358b2a..9c7716c 100644 --- a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp @@ -264,6 +264,7 @@ bool BaseLayerAndroid::prepareBasePictureInGL(SkRect& viewport, float scale, // the two pages (current one and future one with the new scale factor) if (zoomManager->didReceivedRequest()) { float nextTiledPageTransparency = 1; + m_state->resetFrameworkInval(); zoomManager->processTransition(currentTime, scale, &doZoomPageSwap, &nextTiledPageTransparency, &transparency); nextTiledPage->prepareForDrawGL(nextTiledPageTransparency, viewportTileBounds); @@ -370,8 +371,7 @@ bool BaseLayerAndroid::drawGL(IntRect& viewRect, SkRect& visibleRect, updateLayerPositions(visibleRect); // For now, we render layers only if the rendering mode // is kAllTextures or kClippedTextures - if (m_state->layersRenderingMode() < GLWebViewState::kScrollableAndFixedLayers - && compositedRoot->drawGL()) { + if (compositedRoot->drawGL()) { if (TilesManager::instance()->layerTexturesRemain()) { // only try redrawing for layers if layer textures remain, // otherwise we'll repaint without getting anything done diff --git a/Source/WebCore/platform/graphics/android/BaseTile.cpp b/Source/WebCore/platform/graphics/android/BaseTile.cpp index a331dfc..27bd482 100644 --- a/Source/WebCore/platform/graphics/android/BaseTile.cpp +++ b/Source/WebCore/platform/graphics/android/BaseTile.cpp @@ -204,6 +204,7 @@ void BaseTile::markAsDirty(int unsigned pictureCount, } cliperator.next(); } + if (!intersect) return; @@ -268,7 +269,7 @@ void BaseTile::draw(float transparency, SkRect& rect, float scale) } if (m_frontTexture->readyFor(this)) { - if (isLayerTile()) + if (isLayerTile() && m_painter && m_painter->transform()) TilesManager::instance()->shader()->drawLayerQuad(*m_painter->transform(), rect, m_frontTexture->m_ownTextureId, transparency, true); diff --git a/Source/WebCore/platform/graphics/android/ClassTracker.cpp b/Source/WebCore/platform/graphics/android/ClassTracker.cpp index 92d406c..eb810a8 100644 --- a/Source/WebCore/platform/graphics/android/ClassTracker.cpp +++ b/Source/WebCore/platform/graphics/android/ClassTracker.cpp @@ -27,6 +27,7 @@ #include "ClassTracker.h" #include "LayerAndroid.h" +#include "TilesManager.h" #include <cutils/log.h> #include <wtf/CurrentTime.h> @@ -35,6 +36,9 @@ #undef XLOG #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "ClassTracker", __VA_ARGS__) +#define DEBUG_LAYERS +#undef DEBUG_LAYERS + namespace WebCore { ClassTracker* ClassTracker::instance() @@ -66,7 +70,6 @@ void ClassTracker::decrement(String name) m_classes.set(name, value - 1); } - void ClassTracker::add(LayerAndroid* layer) { android::Mutex::Autolock lock(m_lock); @@ -88,6 +91,21 @@ void ClassTracker::show() iter->first.latin1().data(), iter->second); } XLOG("*** %d Layers ***", m_layers.size()); + int nbTextures = 0; + int nbAllocatedTextures = 0; + int nbLayerTextures = 0; + int nbAllocatedLayerTextures = 0; + float textureSize = 256 * 256 * 4 / 1024.0 / 1024.0; + TilesManager::instance()->gatherTexturesNumbers(&nbTextures, &nbAllocatedTextures, + &nbLayerTextures, &nbAllocatedLayerTextures); + XLOG("*** textures: %d/%d (%.2f Mb), layer textures: %d/%d (%.2f Mb) : total used %.2f Mb", + nbAllocatedTextures, nbTextures, + nbAllocatedTextures * textureSize, + nbAllocatedLayerTextures, nbLayerTextures, + nbAllocatedLayerTextures * textureSize, + (nbAllocatedTextures + nbAllocatedLayerTextures) * textureSize); + +#ifdef DEBUG_LAYERS for (unsigned int i = 0; i < m_layers.size(); i++) { LayerAndroid* layer = m_layers[i]; XLOG("[%d/%d] layer %x (%.2f, %.2f) of type %d, refcount(%d) has texture %x has image ref %x (%x) root: %x parent: %x", @@ -98,6 +116,7 @@ void ClassTracker::show() layer->imageTexture(), (LayerAndroid*) layer->getRootLayer(), (LayerAndroid*) layer->getParent()); } +#endif } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/FontAndroid.cpp b/Source/WebCore/platform/graphics/android/FontAndroid.cpp index 81dbdae..0a8c0c1 100644 --- a/Source/WebCore/platform/graphics/android/FontAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/FontAndroid.cpp @@ -98,6 +98,10 @@ static bool setupForText(SkPaint* paint, GraphicsContext* gc, SkLayerDrawLooper* looper = new SkLayerDrawLooper; paint->setLooper(looper)->unref(); + // The layerDrawLooper uses at the root paint to determine the text + // encoding so we need to make sure it is properly configured. + updateForFont(paint, font); + // Specify the behavior of the looper SkLayerDrawLooper::LayerInfo info; info.fPaintBits = SkLayerDrawLooper::kEntirePaint_Bits; diff --git a/Source/WebCore/platform/graphics/android/GLUtils.cpp b/Source/WebCore/platform/graphics/android/GLUtils.cpp index d1fe51a..97a53fe 100644 --- a/Source/WebCore/platform/graphics/android/GLUtils.cpp +++ b/Source/WebCore/platform/graphics/android/GLUtils.cpp @@ -562,6 +562,15 @@ void GLUtils::createTextureFromEGLImage(GLuint texture, EGLImageKHR image, GLint glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); } +void GLUtils::convertToTransformationMatrix(const float* matrix, TransformationMatrix& transformMatrix) +{ + transformMatrix.setMatrix( + matrix[0], matrix[1], matrix[2], matrix[3], + matrix[4], matrix[5], matrix[6], matrix[7], + matrix[8], matrix[9], matrix[10], matrix[11], + matrix[12], matrix[13], matrix[14], matrix[15]); +} + } // namespace WebCore #endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/android/GLUtils.h b/Source/WebCore/platform/graphics/android/GLUtils.h index b952513..68acbab 100644 --- a/Source/WebCore/platform/graphics/android/GLUtils.h +++ b/Source/WebCore/platform/graphics/android/GLUtils.h @@ -83,6 +83,7 @@ public: static void updateSurfaceTextureWithBitmap(const TileRenderInfo* , int x, int y, const SkBitmap& bitmap, GLint filter = GL_LINEAR); #endif static void updateSharedSurfaceTextureWithBitmap(const TileRenderInfo* , int x, int y, const SkBitmap& bitmap); + static void convertToTransformationMatrix(const float* matrix, TransformationMatrix& transformMatrix); }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp index 5206b7a..273c478 100644 --- a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp +++ b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp @@ -84,9 +84,9 @@ GLWebViewState::GLWebViewState() , m_goingLeft(false) , m_expandedTileBoundsX(0) , m_expandedTileBoundsY(0) + , m_highEndGfx(false) , m_scale(1) , m_layersRenderingMode(kAllTextures) - , m_highEndGfx(false) { m_viewport.setEmpty(); m_futureViewportTileBounds.setEmpty(); @@ -150,8 +150,10 @@ void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval TilesManager::instance()->setShowVisualIndicator(showVisualIndicator); } -void GLWebViewState::scrolledLayer(ScrollableLayerAndroid*) +void GLWebViewState::scrollLayer(int layerId, int x, int y) { + m_treeManager.updateScrollableLayer(layerId, x, y); + // TODO: only inval the area of the scrolled layer instead of // doing a fullInval() if (m_layersRenderingMode == kSingleSurfaceRendering) @@ -335,20 +337,25 @@ double GLWebViewState::setupDrawing(IntRect& viewRect, SkRect& visibleRect, int top = viewRect.y(); int width = viewRect.width(); int height = viewRect.height(); - glViewport(left, top, width, height); ShaderProgram* shader = TilesManager::instance()->shader(); if (shader->program() == -1) { XLOG("Reinit shader"); shader->init(); } + shader->setViewport(visibleRect, scale); shader->setViewRect(viewRect); - shader->setViewport(visibleRect); shader->setWebViewRect(webViewRect); shader->setTitleBarHeight(titleBarHeight); shader->setScreenClip(screenClip); shader->resetBlending(); + shader->calculateAnimationDelta(); + + glViewport(left + shader->getAnimationDeltaX(), + top - shader->getAnimationDeltaY(), + width, height); + double currentTime = WTF::currentTime(); setViewport(visibleRect, scale); @@ -379,6 +386,9 @@ bool GLWebViewState::setLayersRenderingMode(TexturesResult& nbTexturesNeeded) if (nbTexturesNeeded.full < maxTextures) m_layersRenderingMode = kAllTextures; + if (!maxTextures && !nbTexturesNeeded.full) + m_layersRenderingMode = kAllTextures; + if (m_layersRenderingMode < layersRenderingMode && m_layersRenderingMode != kAllTextures) invalBase = true; @@ -428,7 +438,8 @@ void GLWebViewState::fullInval() bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, IntRect& webViewRect, int titleBarHeight, - IntRect& clip, float scale, bool* buffersSwappedPtr) + IntRect& clip, float scale, + bool* treesSwappedPtr, bool* newTreeHasAnimPtr) { m_scale = scale; TilesManager::instance()->getProfiler()->nextFrame(viewport.fLeft, @@ -470,7 +481,7 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, // Upload any pending ImageTexture // Return true if we still have some images to upload. // TODO: upload as many textures as possible within a certain time limit - bool ret = ImagesManager::instance()->uploadTextures(); + bool ret = ImagesManager::instance()->prepareTextures(this); if (scale < MIN_SCALE_WARNING || scale > MAX_SCALE_WARNING) XLOGC("WARNING, scale seems corrupted after update: %e", scale); @@ -485,10 +496,18 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, bool fastSwap = isScrolling() || m_layersRenderingMode == kSingleSurfaceRendering; ret |= m_treeManager.drawGL(currentTime, rect, viewport, scale, fastSwap, - buffersSwappedPtr, &nbTexturesNeeded); + treesSwappedPtr, newTreeHasAnimPtr, + &nbTexturesNeeded); if (!ret) resetFrameworkInval(); + int nbTexturesForImages = ImagesManager::instance()->nbTextures(); + XLOG("*** We have %d textures for images, %d full, %d clipped, total %d / %d", + nbTexturesForImages, nbTexturesNeeded.full, nbTexturesNeeded.clipped, + nbTexturesNeeded.full + nbTexturesForImages, + nbTexturesNeeded.clipped + nbTexturesForImages); + nbTexturesNeeded.full += nbTexturesForImages; + nbTexturesNeeded.clipped += nbTexturesForImages; ret |= setLayersRenderingMode(nbTexturesNeeded); FloatRect extrasclip(0, 0, rect.width(), rect.height()); diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.h b/Source/WebCore/platform/graphics/android/GLWebViewState.h index 2a6c8df..8d89704 100644 --- a/Source/WebCore/platform/graphics/android/GLWebViewState.h +++ b/Source/WebCore/platform/graphics/android/GLWebViewState.h @@ -214,7 +214,8 @@ public: bool drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, IntRect& webViewRect, int titleBarHeight, - IntRect& clip, float scale, bool* buffersSwappedPtr); + IntRect& clip, float scale, + bool* treesSwappedPtr, bool* newTreeHasAnimPtr); #ifdef MEASURES_PERF void dumpMeasures(); @@ -247,7 +248,7 @@ public: }; LayersRenderingMode layersRenderingMode() { return m_layersRenderingMode; } - void scrolledLayer(ScrollableLayerAndroid*); + void scrollLayer(int layerId, int x, int y); void invalRegion(const SkRegion& region); diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp index 3e062f8..6990503 100644 --- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp @@ -119,8 +119,8 @@ GraphicsLayerAndroid::GraphicsLayerAndroid(GraphicsLayerClient* client) : m_needsRepaint(false), m_needsNotifyClient(false), m_haveContents(false), - m_haveImage(false), m_newImage(false), + m_image(0), m_foregroundLayer(0), m_foregroundClipLayer(0) { @@ -132,6 +132,9 @@ GraphicsLayerAndroid::GraphicsLayerAndroid(GraphicsLayerClient* client) : GraphicsLayerAndroid::~GraphicsLayerAndroid() { + if (m_image) + m_image->deref(); + m_contentLayer->unref(); SkSafeUnref(m_foregroundLayer); SkSafeUnref(m_foregroundClipLayer); @@ -331,6 +334,9 @@ void GraphicsLayerAndroid::setSize(const FloatSize& size) void GraphicsLayerAndroid::setBackfaceVisibility(bool b) { + if (b == m_backfaceVisibility) + return; + GraphicsLayer::setBackfaceVisibility(b); m_contentLayer->setBackfaceVisibility(b); askForSync(); @@ -397,7 +403,7 @@ void GraphicsLayerAndroid::setDrawsContent(bool drawsContent) void GraphicsLayerAndroid::setBackgroundColor(const Color& color) { - if (color == m_backgroundColor) + if (color == m_backgroundColor && m_backgroundColorSet) return; LOG("(%x) setBackgroundColor", this); GraphicsLayer::setBackgroundColor(color); @@ -409,6 +415,9 @@ void GraphicsLayerAndroid::setBackgroundColor(const Color& color) void GraphicsLayerAndroid::clearBackgroundColor() { + if (!m_backgroundColorSet) + return; + LOG("(%x) clearBackgroundColor", this); GraphicsLayer::clearBackgroundColor(); askForSync(); @@ -551,7 +560,7 @@ bool GraphicsLayerAndroid::repaint() LOG("(%x) repaint(), gPaused(%d) m_needsRepaint(%d) m_haveContents(%d) ", this, gPaused, m_needsRepaint, m_haveContents); - if (!gPaused && m_haveContents && m_needsRepaint && !m_haveImage) { + if (!gPaused && m_haveContents && m_needsRepaint && !m_image) { // with SkPicture, we request the entire layer's content. IntRect layerBounds(0, 0, m_size.width(), m_size.height()); @@ -602,7 +611,14 @@ bool GraphicsLayerAndroid::repaint() m_foregroundLayer->setPosition(-x, -y); // Set the scrollable bounds of the layer. m_foregroundLayer->setScrollLimits(-x, -y, m_size.width(), m_size.height()); - m_foregroundLayer->markAsDirty(m_dirtyRegion); + + // Invalidate the entire layer for now, as webkit will only send the + // setNeedsDisplayInRect() for the visible (clipped) scrollable area, + // offsetting the invals by the scroll position would not be enough. + // TODO: have webkit send us invals even for non visible area + SkRegion region; + region.setRect(0, 0, contentsRect.width(), contentsRect.height()); + m_foregroundLayer->markAsDirty(region); m_foregroundLayer->needsRepaint(); } else { // If there is no contents clip, we can draw everything into one @@ -633,7 +649,7 @@ bool GraphicsLayerAndroid::repaint() return true; } - if (m_needsRepaint && m_haveImage && m_newImage) { + if (m_needsRepaint && m_image && m_newImage) { // We need to tell the GL thread that we will need to repaint the // texture. Only do so if we effectively have a new image! m_contentLayer->markAsDirty(m_dirtyRegion); @@ -666,7 +682,7 @@ void GraphicsLayerAndroid::setNeedsDisplayInRect(const FloatRect& rect) { // rect is in the render object coordinates - if (!m_haveImage && !drawsContent()) { + if (!m_image && !drawsContent()) { LOG("(%x) setNeedsDisplay(%.2f,%.2f,%.2f,%.2f) doesn't have content, bypass...", this, rect.x(), rect.y(), rect.width(), rect.height()); return; @@ -830,14 +846,23 @@ void GraphicsLayerAndroid::resumeAnimations() void GraphicsLayerAndroid::setContentsToImage(Image* image) { TLOG("(%x) setContentsToImage", this, image); - if (image) { + if (image && image != m_image) { + image->ref(); + if (m_image) + m_image->deref(); + m_image = image; + + SkBitmapRef* bitmap = image->nativeImageForCurrentFrame(); + m_contentLayer->setContentsImage(bitmap); + m_haveContents = true; - m_haveImage = true; m_newImage = true; - m_contentLayer->setContentsImage(image->nativeImageForCurrentFrame()); } - if (m_haveImage && !image) + if (!image && m_image) { m_contentLayer->setContentsImage(0); + m_image->deref(); + m_image = 0; + } setNeedsDisplay(); askForSync(); diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h index af8d7ce..358f674 100644 --- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h @@ -145,8 +145,8 @@ private: bool m_needsNotifyClient; bool m_haveContents; - bool m_haveImage; bool m_newImage; + Image* m_image; SkRegion m_dirtyRegion; diff --git a/Source/WebCore/platform/graphics/android/ImageTexture.cpp b/Source/WebCore/platform/graphics/android/ImageTexture.cpp index 96f7713..23e3899 100644 --- a/Source/WebCore/platform/graphics/android/ImageTexture.cpp +++ b/Source/WebCore/platform/graphics/android/ImageTexture.cpp @@ -27,8 +27,11 @@ #include "ImageTexture.h" #include "ImagesManager.h" +#include "LayerAndroid.h" #include "SkDevice.h" +#include "SkPicture.h" #include "TilesManager.h" +#include "TiledTexture.h" #include <cutils/log.h> #include <wtf/CurrentTime.h> @@ -51,96 +54,201 @@ namespace WebCore { -ImageTexture::ImageTexture(SkBitmapRef* img) - : m_imageRef(img) - , m_image(0) - , m_textureId(0) - , m_refCount(0) +// CRC computation adapted from Tools/DumpRenderTree/CyclicRedundancyCheck.cpp +static void makeCrcTable(unsigned crcTable[256]) +{ + for (unsigned i = 0; i < 256; i++) { + unsigned c = i; + for (int k = 0; k < 8; k++) { + if (c & 1) + c = -306674912 ^ ((c >> 1) & 0x7fffffff); + else + c = c >> 1; + } + crcTable[i] = c; + } +} + +unsigned computeCrc(uint8_t* buffer, size_t size) +{ + static unsigned crcTable[256]; + static bool crcTableComputed = false; + if (!crcTableComputed) { + makeCrcTable(crcTable); + crcTableComputed = true; + } + + unsigned crc = 0xffffffffL; + for (size_t i = 0; i < size; ++i) + crc = crcTable[(crc ^ buffer[i]) & 0xff] ^ ((crc >> 8) & 0x00ffffffL); + return crc ^ 0xffffffffL; +} + +ImageTexture::ImageTexture(SkBitmap* bmp, unsigned crc) + : m_image(bmp) + , m_texture(0) + , m_layer(0) + , m_picture(0) + , m_crc(crc) { #ifdef DEBUG_COUNT ClassTracker::instance()->increment("ImageTexture"); #endif - if (!m_imageRef) + if (!m_image) return; - SkBitmap* bitmap = &m_imageRef->bitmap(); - m_image = new SkBitmap(); + // NOTE: This constructor is called on the webcore thread + + // Create a picture containing the image (needed for TiledTexture) + m_picture = new SkPicture(); + SkCanvas* pcanvas = m_picture->beginRecording(m_image->width(), m_image->height()); + pcanvas->clear(SkColorSetARGBInline(0, 0, 0, 0)); + pcanvas->drawBitmap(*m_image, 0, 0); + m_picture->endRecording(); +} + +ImageTexture::~ImageTexture() +{ +#ifdef DEBUG_COUNT + ClassTracker::instance()->decrement("ImageTexture"); +#endif + delete m_image; + delete m_texture; + SkSafeUnref(m_picture); +} + +SkBitmap* ImageTexture::convertBitmap(SkBitmap* bitmap) +{ + SkBitmap* img = new SkBitmap(); int w = bitmap->width(); int h = bitmap->height(); - m_image->setConfig(SkBitmap::kARGB_8888_Config, w, h); - m_image->allocPixels(); - SkDevice* device = new SkDevice(NULL, *m_image, false); + + // Create a copy of the image + img->setConfig(SkBitmap::kARGB_8888_Config, w, h); + img->allocPixels(); + SkDevice* device = new SkDevice(NULL, *img, false); SkCanvas canvas; canvas.setDevice(device); device->unref(); SkRect dest; dest.set(0, 0, w, h); - m_image->setIsOpaque(false); - m_image->eraseARGB(0, 0, 0, 0); + img->setIsOpaque(false); + img->eraseARGB(0, 0, 0, 0); canvas.drawBitmapRect(*bitmap, 0, dest); + + return img; } -ImageTexture::~ImageTexture() +unsigned ImageTexture::computeCRC(const SkBitmap* bitmap) { -#ifdef DEBUG_COUNT - ClassTracker::instance()->decrement("ImageTexture"); -#endif - delete m_image; + if (!bitmap) + return 0; + bitmap->lockPixels(); + uint8_t* img = static_cast<uint8_t*>(bitmap->getPixels()); + unsigned crc = computeCrc(img, bitmap->getSize()); + bitmap->unlockPixels(); + return crc; } -void ImageTexture::prepareGL() +bool ImageTexture::equalsCRC(unsigned crc) { - if (m_textureId) - return; - - ImagesManager::instance()->scheduleTextureUpload(this); + return m_crc == crc; } -void ImageTexture::uploadGLTexture() +int ImageTexture::nbTextures() { - if (m_textureId) - return; - - glGenTextures(1, &m_textureId); - GLUtils::createTextureWithBitmap(m_textureId, *m_image); + if (!hasContentToShow()) + return 0; + if (!m_texture) + return 0; + + // TODO: take in account the visible clip (need to maintain + // a list of the clients layer, etc.) + IntRect visibleArea(0, 0, m_image->width(), m_image->height()); + int nbTextures = m_texture->nbTextures(visibleArea, 1.0); + XLOG("ImageTexture %p, %d x %d needs %d textures", + this, m_image->width(), m_image->height(), + nbTextures); + return nbTextures; } -void ImageTexture::drawGL(LayerAndroid* layer) +bool ImageTexture::hasContentToShow() { - if (!layer) - return; - if (!m_textureId) - return; + // Don't display 1x1 image -- no need to allocate a full texture for this if (!m_image) - return; + return false; + if (m_image->width() == 1 && m_image->height() == 1) + return false; + return true; +} - SkRect rect; - rect.fLeft = 0; - rect.fTop = 0; - rect.fRight = layer->getSize().width(); - rect.fBottom = layer->getSize().height(); - TilesManager::instance()->shader()->drawLayerQuad(*layer->drawTransform(), - rect, m_textureId, - layer->drawOpacity(), true); +bool ImageTexture::prepareGL(GLWebViewState* state) +{ + if (!hasContentToShow()) + return false; + + if (!m_texture && m_picture) { + m_texture = new TiledTexture(this); + SkRegion region; + region.setRect(0, 0, m_image->width(), m_image->height()); + m_texture->update(region, m_picture); + } + + if (!m_texture) + return false; + + IntRect visibleArea(0, 0, m_image->width(), m_image->height()); + m_texture->prepare(state, 1.0, true, true, visibleArea); + if (m_texture->ready()) { + m_texture->swapTiles(); + return false; + } + return true; } -void ImageTexture::drawCanvas(SkCanvas* canvas, SkRect& rect) +const TransformationMatrix* ImageTexture::transform() { - canvas->drawBitmapRect(*m_image, 0, rect); + if (!m_layer) + return 0; + + FloatPoint p(0, 0); + p = m_layer->drawTransform()->mapPoint(p); + IntRect layerArea = m_layer->unclippedArea(); + float scaleW = static_cast<float>(layerArea.width()) / static_cast<float>(m_image->width()); + float scaleH = static_cast<float>(layerArea.height()) / static_cast<float>(m_image->height()); + TransformationMatrix d = *(m_layer->drawTransform()); + TransformationMatrix m; + m.scaleNonUniform(scaleW, scaleH); + m_layerMatrix = d.multiply(m); + return &m_layerMatrix; } -void ImageTexture::release() +float ImageTexture::opacity() { - if (m_refCount >= 1) - m_refCount--; - if (!m_refCount) - deleteTexture(); + if (!m_layer) + return 1.0; + return m_layer->drawOpacity(); } -void ImageTexture::deleteTexture() +void ImageTexture::drawGL(LayerAndroid* layer) +{ + if (!layer) + return; + if (!hasContentToShow()) + return; + + // TiledTexture::draw() will call us back to know the + // transform and opacity, so we need to set m_layer + m_layer = layer; + if (m_texture) + m_texture->draw(); + m_layer = 0; +} + +void ImageTexture::drawCanvas(SkCanvas* canvas, SkRect& rect) { - if (m_textureId) - glDeleteTextures(1, &m_textureId); + if (canvas && m_image) + canvas->drawBitmapRect(*m_image, 0, rect); } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/ImageTexture.h b/Source/WebCore/platform/graphics/android/ImageTexture.h index cea79c3..6c6a075 100644 --- a/Source/WebCore/platform/graphics/android/ImageTexture.h +++ b/Source/WebCore/platform/graphics/android/ImageTexture.h @@ -29,57 +29,78 @@ #include "GLUtils.h" #include "SkBitmap.h" #include "SkBitmapRef.h" +#include "SkPicture.h" #include "SkRefCnt.h" #include "LayerAndroid.h" namespace WebCore { class LayerAndroid; +class TexturesResult; +class TiledTexture; ///////////////////////////////////////////////////////////////////////////////// // Image sharing codepath for layers ///////////////////////////////////////////////////////////////////////////////// // -// We receive an SkBitmapRef on the webcore thread; from this we create -// an ImageTexture instance and keep it in TilesManager in a hashmap -// (see TilesManager::addImage()) +// Layers containing only an image take a slightly different codepath; +// GraphicsLayer::setContentsToImage() is called on the webcore thread, +// passing an Image instance. We get the native image (an SkBitmap) and create +// an ImageTexture instance with it (or increment the refcount of an existing +// instance if the SkBitmap is similar to one already stored in ImagesManager, +// i.e. if two GraphicsLayer share the same image). // -// The ImageTexture will recopy the pointed SkBitmap locally (so we can safely -// use it on the texture generation thread), and just use the SkBitmapRef as a -// key. +// To detect if an image is similar, we compute and use a CRC. Each ImageTexture +// is stored in ImagesManager using its CRC as a hash key. +// Simply comparing the address is not enough -- different image could end up +// at the same address (i.e. the image is deallocated then a new one is +// reallocated at the old address) // -// Layers on the shared image path will ask TilesManager for the corresponding -// ImageTexture, instead of using a PaintedSurface+TiledTexture. -// When the ImageTexture is prepared for the first time, we directly upload -// the bitmap to a texture. +// Each ImageTexture's CRC being unique, LayerAndroid instances simply store that +// and retain/release the corresponding ImageTexture (so that +// queued painting request will work correctly and not crash...). +// LayerAndroid running on the UI thread will get the corresponding +// ImageTexture at draw time. // -// TODO: limit how many ImageTextures can be uploaded in one draw cycle -// TODO: limit the size of ImageTextures (use a TiledTexture when needed) +// ImageTexture recopy the original SkBitmap so that they can safely be used +// on a different thread; it uses TiledTexture to allocate and paint the image, +// so that we can share the same textures and limits as the rest of the layers. // ///////////////////////////////////////////////////////////////////////////////// -class ImageTexture { +class ImageTexture : public SurfacePainter { public: - ImageTexture(SkBitmapRef* img); + ImageTexture(SkBitmap* bmp, unsigned crc); virtual ~ImageTexture(); - void prepareGL(); - void uploadGLTexture(); + bool prepareGL(GLWebViewState*); void drawGL(LayerAndroid* painter); void drawCanvas(SkCanvas*, SkRect&); - void retain() { m_refCount++; } - void release(); - unsigned int refCount() { return m_refCount; } - SkBitmapRef* imageRef() { return m_imageRef; } + bool hasContentToShow(); SkBitmap* bitmap() { return m_image; } + unsigned imageCRC() { return m_crc; } -private: + static SkBitmap* convertBitmap(SkBitmap* bitmap); + + static unsigned computeCRC(const SkBitmap* bitmap); + bool equalsCRC(unsigned crc); + + // methods used by TiledTexture + virtual const TransformationMatrix* transform(); + virtual float opacity(); - void deleteTexture(); + int nbTextures(); + + virtual SurfaceType type() { return SurfacePainter::ImageSurface; } + +private: SkBitmapRef* m_imageRef; SkBitmap* m_image; - GLuint m_textureId; - unsigned int m_refCount; + TiledTexture* m_texture; + LayerAndroid* m_layer; + SkPicture* m_picture; + TransformationMatrix m_layerMatrix; + unsigned m_crc; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/ImagesManager.cpp b/Source/WebCore/platform/graphics/android/ImagesManager.cpp index 21f9fe9..65c41d1 100644 --- a/Source/WebCore/platform/graphics/android/ImagesManager.cpp +++ b/Source/WebCore/platform/graphics/android/ImagesManager.cpp @@ -26,6 +26,9 @@ #include "config.h" #include "ImagesManager.h" +#include "SkCanvas.h" +#include "SkDevice.h" +#include "SkRefCnt.h" #include "ImageTexture.h" #include <cutils/log.h> @@ -59,71 +62,88 @@ ImagesManager* ImagesManager::instance() ImagesManager* ImagesManager::gInstance = 0; -void ImagesManager::addImage(SkBitmapRef* imgRef) +ImageTexture* ImagesManager::setImage(SkBitmapRef* imgRef) { if (!imgRef) - return; + return 0; + + SkBitmap* bitmap = &imgRef->bitmap(); + ImageTexture* image = 0; + SkBitmap* img = 0; + unsigned crc = 0; + + img = ImageTexture::convertBitmap(bitmap); + crc = ImageTexture::computeCRC(img); + + { + android::Mutex::Autolock lock(m_imagesLock); + if (m_images.contains(crc)) { + image = m_images.get(crc); + SkSafeRef(image); + return image; + } + } + + // the image is not in the map, we add it + + image = new ImageTexture(img, crc); android::Mutex::Autolock lock(m_imagesLock); - if (!m_images.contains(imgRef)) - m_images.set(imgRef, new ImageTexture(imgRef)); + m_images.set(crc, image); + + return image; } -void ImagesManager::removeImage(SkBitmapRef* imgRef) +ImageTexture* ImagesManager::retainImage(unsigned imgCRC) { + if (!imgCRC) + return 0; + android::Mutex::Autolock lock(m_imagesLock); - if (!m_images.contains(imgRef)) - return; + ImageTexture* image = 0; + if (m_images.contains(imgCRC)) { + image = m_images.get(imgCRC); + SkSafeRef(image); + } + return image; +} - ImageTexture* image = m_images.get(imgRef); - image->release(); +void ImagesManager::releaseImage(unsigned imgCRC) +{ + if (!imgCRC) + return; - if (!image->refCount()) { - m_images.remove(imgRef); - delete image; + android::Mutex::Autolock lock(m_imagesLock); + if (m_images.contains(imgCRC)) { + ImageTexture* image = m_images.get(imgCRC); + if (image->getRefCnt() == 1) + m_images.remove(imgCRC); + SkSafeUnref(image); } } -void ImagesManager::showImages() +int ImagesManager::nbTextures() { - XLOGC("We have %d images", m_images.size()); - HashMap<SkBitmapRef*, ImageTexture*>::iterator end = m_images.end(); + android::Mutex::Autolock lock(m_imagesLock); + HashMap<unsigned, ImageTexture*>::iterator end = m_images.end(); int i = 0; - for (HashMap<SkBitmapRef*, ImageTexture*>::iterator it = m_images.begin(); it != end; ++it) { - XLOGC("Image %x (%d/%d) has %d references", it->first, i, - m_images.size(), it->second->refCount()); + int nb = 0; + for (HashMap<unsigned, ImageTexture*>::iterator it = m_images.begin(); it != end; ++it) { + nb += it->second->nbTextures(); i++; } + return nb; } -ImageTexture* ImagesManager::getTextureForImage(SkBitmapRef* img, bool retain) +bool ImagesManager::prepareTextures(GLWebViewState* state) { + bool ret = false; android::Mutex::Autolock lock(m_imagesLock); - ImageTexture* image = m_images.get(img); - if (retain && image) - image->retain(); - return image; -} - -void ImagesManager::scheduleTextureUpload(ImageTexture* texture) -{ - if (m_imagesToUpload.contains(texture)) - return; - - texture->retain(); - m_imagesToUpload.append(texture); -} - -bool ImagesManager::uploadTextures() -{ - // scheduleUpload and uploadTextures are called on the same thread - if (!m_imagesToUpload.size()) - return false; - ImageTexture* texture = m_imagesToUpload.last(); - texture->uploadGLTexture(); - m_imagesToUpload.removeLast(); - removeImage(texture->imageRef()); - return m_imagesToUpload.size(); + HashMap<unsigned, ImageTexture*>::iterator end = m_images.end(); + for (HashMap<unsigned, ImageTexture*>::iterator it = m_images.begin(); it != end; ++it) { + ret |= it->second->prepareGL(state); + } + return ret; } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/ImagesManager.h b/Source/WebCore/platform/graphics/android/ImagesManager.h index 2fcb9fd..a3ea859 100644 --- a/Source/WebCore/platform/graphics/android/ImagesManager.h +++ b/Source/WebCore/platform/graphics/android/ImagesManager.h @@ -35,17 +35,18 @@ namespace WebCore { class ImageTexture; +class GLWebViewState; class ImagesManager { public: static ImagesManager* instance(); - void addImage(SkBitmapRef* img); - void removeImage(SkBitmapRef* img); - ImageTexture* getTextureForImage(SkBitmapRef* img, bool retain = true); - void showImages(); - void scheduleTextureUpload(ImageTexture* texture); - bool uploadTextures(); + ImageTexture* setImage(SkBitmapRef* imgRef); + ImageTexture* retainImage(unsigned imgCRC); + void releaseImage(unsigned imgCRC); + + bool prepareTextures(GLWebViewState*); + int nbTextures(); private: ImagesManager() {} @@ -53,8 +54,7 @@ private: static ImagesManager* gInstance; android::Mutex m_imagesLock; - HashMap<SkBitmapRef*, ImageTexture*> m_images; - Vector<ImageTexture*> m_imagesToUpload; + HashMap<unsigned, ImageTexture*> m_images; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp index 9e7626a..962bcdf 100644 --- a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp @@ -149,8 +149,7 @@ LayerAndroid::LayerAndroid(RenderLayer* owner) : Layer(), m_recordingPicture(0), m_uniqueId(++gUniqueId), m_texture(0), - m_imageRef(0), - m_imageTexture(0), + m_imageCRC(0), m_pictureUsed(0), m_scale(1), m_lastComputeTextureSize(0), @@ -174,15 +173,15 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : Layer(layer), m_isIframe(layer.m_isIframe), m_uniqueId(layer.m_uniqueId), m_texture(0), - m_imageTexture(0), m_owningLayer(layer.m_owningLayer), m_type(LayerAndroid::UILayer), m_hasText(true) { m_isFixed = layer.m_isFixed; - m_imageRef = layer.m_imageRef; - if (m_imageRef) - ImagesManager::instance()->addImage(m_imageRef); + m_imageCRC = layer.m_imageCRC; + if (m_imageCRC) + ImagesManager::instance()->retainImage(m_imageCRC); + m_renderLayerPos = layer.m_renderLayerPos; m_transform = layer.m_transform; m_backfaceVisibility = layer.m_backfaceVisibility; @@ -216,14 +215,13 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : Layer(layer), KeyframesMap::const_iterator end = layer.m_animations.end(); for (KeyframesMap::const_iterator it = layer.m_animations.begin(); it != end; ++it) { - pair<String, int> key((it->second)->name(), (it->second)->type()); - m_animations.add(key, (it->second)->copy()); + m_animations.add(it->first, it->second); } m_hasText = layer.m_hasText; #ifdef DEBUG_COUNT - ClassTracker::instance()->increment("LayerAndroid - recopy (UI?)"); + ClassTracker::instance()->increment("LayerAndroid - recopy (UI)"); ClassTracker::instance()->add(this); #endif } @@ -252,8 +250,7 @@ LayerAndroid::LayerAndroid(SkPicture* picture) : Layer(), m_recordingPicture(picture), m_uniqueId(++gUniqueId), m_texture(0), - m_imageRef(0), - m_imageTexture(0), + m_imageCRC(0), m_scale(1), m_lastComputeTextureSize(0), m_owningLayer(0), @@ -272,8 +269,9 @@ LayerAndroid::LayerAndroid(SkPicture* picture) : Layer(), LayerAndroid::~LayerAndroid() { - if (m_imageTexture) - ImagesManager::instance()->removeImage(m_imageTexture->imageRef()); + if (m_imageCRC) + ImagesManager::instance()->releaseImage(m_imageCRC); + SkSafeUnref(m_recordingPicture); m_animations.clear(); #ifdef DEBUG_COUNT @@ -326,6 +324,17 @@ bool LayerAndroid::evaluateAnimations(double time) return hasRunningAnimations || m_hasRunningAnimations; } +void LayerAndroid::initAnimations() { + // tell auto-initializing animations to start now + for (int i = 0; i < countChildren(); i++) + getChild(i)->initAnimations(); + + KeyframesMap::const_iterator localBegin = m_animations.begin(); + KeyframesMap::const_iterator localEnd = m_animations.end(); + for (KeyframesMap::const_iterator localIt = localBegin; localIt != localEnd; ++localIt) + (localIt->second)->suggestBeginTime(WTF::currentTime()); +} + void LayerAndroid::addDirtyArea() { IntSize layerSize(getSize().width(), getSize().height()); @@ -370,7 +379,7 @@ void LayerAndroid::removeAnimationsForKeyframes(const String& name) } for (unsigned int i = 0; i < toDelete.size(); i++) - m_animations.remove(toDelete[i]); + m_animations.remove(toDelete[i]); } // We only use the bounding rect of the layer as mask... @@ -761,16 +770,14 @@ void LayerAndroid::updateGLPositionsAndScale(const TransformationMatrix& parentM void LayerAndroid::setContentsImage(SkBitmapRef* img) { - m_imageRef = img; - if (!img) - return; - - ImagesManager::instance()->addImage(img); + ImageTexture* image = ImagesManager::instance()->setImage(img); + ImagesManager::instance()->releaseImage(m_imageCRC); + m_imageCRC = image ? image->imageCRC() : 0; } bool LayerAndroid::needsTexture() { - return m_imageRef || (m_recordingPicture + return m_imageCRC || (m_recordingPicture && m_recordingPicture->width() && m_recordingPicture->height()); } @@ -841,10 +848,11 @@ void LayerAndroid::showLayer(int indent) IntRect visible = visibleArea(); IntRect clip(m_clippingRect.x(), m_clippingRect.y(), m_clippingRect.width(), m_clippingRect.height()); - XLOGC("%s [%d:0x%x] - %s - area (%d, %d, %d, %d) - visible (%d, %d, %d, %d) " + XLOGC("%s [%d:0x%x] - %s %s - area (%d, %d, %d, %d) - visible (%d, %d, %d, %d) " "clip (%d, %d, %d, %d) %s %s prepareContext(%x), pic w: %d h: %d", spaces, uniqueId(), m_owningLayer, needsTexture() ? "needs a texture" : "no texture", + m_imageCRC ? "has an image" : "no image", tr.x(), tr.y(), tr.width(), tr.height(), visible.x(), visible.y(), visible.width(), visible.height(), clip.x(), clip.y(), clip.width(), clip.height(), @@ -889,7 +897,12 @@ void LayerAndroid::setIsPainting(Layer* drawingTree) for (int i = 0; i < count; i++) this->getChild(i)->setIsPainting(drawingTree); - obtainTextureForPainting(static_cast<LayerAndroid*>(drawingTree)); + + LayerAndroid* drawingLayer = 0; + if (drawingTree) + drawingLayer = static_cast<LayerAndroid*>(drawingTree)->findById(uniqueId()); + + obtainTextureForPainting(drawingLayer); } void LayerAndroid::mergeInvalsInto(Layer* replacementTree) @@ -950,38 +963,31 @@ bool LayerAndroid::updateWithLayer(LayerAndroid* layer) m_opacity = layer->m_opacity; m_transform = layer->m_transform; - if (m_imageRef != layer->m_imageRef) + if (m_imageCRC != layer->m_imageCRC) m_visible = false; if ((m_recordingPicture != layer->m_recordingPicture) - || (m_imageRef != layer->m_imageRef)) + || (m_imageCRC != layer->m_imageCRC)) return true; return false; } -void LayerAndroid::obtainTextureForPainting(LayerAndroid* drawingTree) +void LayerAndroid::obtainTextureForPainting(LayerAndroid* drawingLayer) { if (!needsTexture()) return; - if (m_imageRef) { - if (!m_imageTexture) { - m_imageTexture = ImagesManager::instance()->getTextureForImage(m_imageRef); - m_dirtyRegion.setEmpty(); - } + if (m_imageCRC) { if (m_texture) { m_texture->setDrawingLayer(0); m_texture->clearPaintingLayer(); m_texture = 0; } } else { - if (drawingTree) { - LayerAndroid* drawingLayer = drawingTree->findById(uniqueId()); - if (drawingLayer) { - // if a previous tree had the same layer, paint with that painted surface - m_texture = drawingLayer->m_texture; - } + if (drawingLayer) { + // if a previous tree had the same layer, paint with that painted surface + m_texture = drawingLayer->m_texture; } if (!m_texture) @@ -989,8 +995,8 @@ void LayerAndroid::obtainTextureForPainting(LayerAndroid* drawingTree) // pass the invalidated regions to the PaintedSurface m_texture->setPaintingLayer(this, m_dirtyRegion); - m_dirtyRegion.setEmpty(); } + m_dirtyRegion.setEmpty(); } @@ -1032,9 +1038,6 @@ void LayerAndroid::prepare() if (m_texture) m_texture->prepare(m_state); - - if (m_imageTexture) - m_imageTexture->prepareGL(); } IntRect LayerAndroid::unclippedArea() @@ -1115,11 +1118,16 @@ bool LayerAndroid::drawGL() bool askScreenUpdate = false; - if (m_texture) - askScreenUpdate |= m_texture->draw(); - - if (m_imageTexture) - m_imageTexture->drawGL(this); + if (m_state->layersRenderingMode() < GLWebViewState::kScrollableAndFixedLayers) { + if (m_texture) + askScreenUpdate |= m_texture->draw(); + if (m_imageCRC) { + ImageTexture* imageTexture = ImagesManager::instance()->retainImage(m_imageCRC); + if (imageTexture) + imageTexture->drawGL(this); + ImagesManager::instance()->releaseImage(m_imageCRC); + } + } // When the layer is dirty, the UI thread should be notified to redraw. askScreenUpdate |= drawChildrenGL(); @@ -1216,16 +1224,15 @@ void LayerAndroid::onDraw(SkCanvas* canvas, SkScalar opacity) if (canvasOpacity < 255) canvas->setDrawFilter(new OpacityDrawFilter(canvasOpacity)); - if (m_imageRef) { - if (!m_imageTexture) { - m_imageTexture = ImagesManager::instance()->getTextureForImage(m_imageRef); - m_dirtyRegion.setEmpty(); - } - if (m_imageTexture) { + if (m_imageCRC) { + ImageTexture* imageTexture = ImagesManager::instance()->retainImage(m_imageCRC); + m_dirtyRegion.setEmpty(); + if (imageTexture) { SkRect dest; dest.set(0, 0, getSize().width(), getSize().height()); - m_imageTexture->drawCanvas(canvas, dest); + imageTexture->drawCanvas(canvas, dest); } + ImagesManager::instance()->releaseImage(m_imageCRC); } contentDraw(canvas); } diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.h b/Source/WebCore/platform/graphics/android/LayerAndroid.h index ae9dc88..c1f1bc9 100644 --- a/Source/WebCore/platform/graphics/android/LayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/LayerAndroid.h @@ -214,6 +214,7 @@ public: void removeAnimationsForKeyframes(const String& name); bool evaluateAnimations(); bool evaluateAnimations(double time); + void initAnimations(); bool hasAnimations() const; void addDirtyArea(); @@ -260,7 +261,7 @@ public: /** This sets a content image -- calling it means we will use the image directly when drawing the layer instead of using the content painted by WebKit. - Images are handled in TilesManager, as they can be shared + Images are handled in ImagesManager, as they can be shared between layers. */ void setContentsImage(SkBitmapRef* img); @@ -290,7 +291,7 @@ public: friend void android::cleanupImageRefs(LayerAndroid* layer); PaintedSurface* texture() { return m_texture; } - void obtainTextureForPainting(LayerAndroid* drawingTree); + void obtainTextureForPainting(LayerAndroid* drawingLayer); // Update layers using another tree. Only works for basic properties // such as the position, the transform. Return true if anything more @@ -298,13 +299,13 @@ public: bool updateWithTree(LayerAndroid*); virtual bool updateWithLayer(LayerAndroid*); - SkBitmapRef* imageRef() { return m_imageRef; } - ImageTexture* imageTexture() { return m_imageTexture; } int type() { return m_type; } bool hasText() { return m_hasText; } void checkTextPresence(); + void copyAnimationStartTimesRecursive(LayerAndroid* oldTree); + // rendering asset management void swapTiles(); void setIsDrawing(bool isDrawing); @@ -323,6 +324,7 @@ private: friend class CachedLayer::Debug; // debugging access only #endif + void copyAnimationStartTimes(LayerAndroid* oldLayer); void findInner(FindState&) const; bool prepareContext(bool force = false); void clipInner(SkTDArray<SkRect>* region, const SkRect& local) const; @@ -386,8 +388,7 @@ private: int m_uniqueId; PaintedSurface* m_texture; - SkBitmapRef* m_imageRef; - ImageTexture* m_imageTexture; + unsigned m_imageCRC; unsigned int m_pictureUsed; diff --git a/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp b/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp index 5d06ea3..2d69706 100644 --- a/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp +++ b/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp @@ -25,12 +25,14 @@ #include "config.h" #include "PaintTileOperation.h" +#include "ImageTexture.h" +#include "ImagesManager.h" #include "LayerAndroid.h" #include "PaintedSurface.h" namespace WebCore { -PaintTileOperation::PaintTileOperation(BaseTile* tile, PaintedSurface* surface) +PaintTileOperation::PaintTileOperation(BaseTile* tile, SurfacePainter* surface) : QueuedOperation(QueuedOperation::PaintTile, tile->page()) , m_tile(tile) , m_surface(surface) @@ -46,7 +48,13 @@ PaintTileOperation::~PaintTileOperation() m_tile->setRepaintPending(false); m_tile = 0; } - SkSafeUnref(m_surface); + + if (m_surface && m_surface->type() == SurfacePainter::ImageSurface) { + ImageTexture* image = static_cast<ImageTexture*>(m_surface); + ImagesManager::instance()->releaseImage(image->imageCRC()); + } else { + SkSafeUnref(m_surface); + } } bool PaintTileOperation::operator==(const QueuedOperation* operation) diff --git a/Source/WebCore/platform/graphics/android/PaintTileOperation.h b/Source/WebCore/platform/graphics/android/PaintTileOperation.h index fabc2f7..bc74d03 100644 --- a/Source/WebCore/platform/graphics/android/PaintTileOperation.h +++ b/Source/WebCore/platform/graphics/android/PaintTileOperation.h @@ -28,15 +28,17 @@ #include "BaseTile.h" #include "QueuedOperation.h" +#include "SkRefCnt.h" namespace WebCore { class LayerAndroid; -class PaintedSurface; +class SurfacePainter; +class ImageTexture; class PaintTileOperation : public QueuedOperation { public: - PaintTileOperation(BaseTile* tile, PaintedSurface* surface = 0); + PaintTileOperation(BaseTile* tile, SurfacePainter* surface = 0); virtual ~PaintTileOperation(); virtual bool operator==(const QueuedOperation* operation); virtual void run(); @@ -47,7 +49,7 @@ public: private: BaseTile* m_tile; - PaintedSurface* m_surface; + SurfacePainter* m_surface; }; class ScaleFilter : public OperationFilter { diff --git a/Source/WebCore/platform/graphics/android/PaintedSurface.cpp b/Source/WebCore/platform/graphics/android/PaintedSurface.cpp index d3c1e15..45c7579 100644 --- a/Source/WebCore/platform/graphics/android/PaintedSurface.cpp +++ b/Source/WebCore/platform/graphics/android/PaintedSurface.cpp @@ -52,9 +52,8 @@ #endif // DEBUG -// Allows layers using less than MAX_UNCLIPPED_AREA tiles to -// schedule all of them instead of clipping the area with the visible rect. -#define MAX_UNCLIPPED_AREA 16 +// Layers with an area larger than 2048*2048 should never be unclipped +#define MAX_UNCLIPPED_AREA 4194304 namespace WebCore { @@ -203,10 +202,14 @@ IntRect PaintedSurface::computeVisibleArea(LayerAndroid* layer) { return area; if (!layer->contentIsScrollable() - && layer->state()->layersRenderingMode() == GLWebViewState::kAllTextures) + && layer->state()->layersRenderingMode() == GLWebViewState::kAllTextures) { area = layer->unclippedArea(); - else + double total = ((double) area.width()) * ((double) area.height()); + if (total > MAX_UNCLIPPED_AREA) + area = layer->visibleArea(); + } else { area = layer->visibleArea(); + } return area; } diff --git a/Source/WebCore/platform/graphics/android/PaintedSurface.h b/Source/WebCore/platform/graphics/android/PaintedSurface.h index b438111..b8ab7b8 100644 --- a/Source/WebCore/platform/graphics/android/PaintedSurface.h +++ b/Source/WebCore/platform/graphics/android/PaintedSurface.h @@ -43,7 +43,7 @@ namespace WebCore { class DualTiledTexture; -class PaintedSurface : public SkRefCnt { +class PaintedSurface : public SurfacePainter { public: PaintedSurface(); virtual ~PaintedSurface(); @@ -71,10 +71,10 @@ public: // TilePainter methods for TiledTexture virtual const TransformationMatrix* transform(); + virtual float opacity(); // used by TiledTexture float scale() { return m_scale; } - float opacity(); unsigned int pictureUsed() { return m_pictureUsed; } private: diff --git a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp index 2643d2c..3c2ced5 100644 --- a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp @@ -22,9 +22,6 @@ bool ScrollableLayerAndroid::scrollTo(int x, int y) setPosition(m_scrollLimits.fLeft - newX, m_scrollLimits.fTop - newY); - if (state()) - state()->scrolledLayer(this); - return true; } diff --git a/Source/WebCore/platform/graphics/android/ShaderProgram.cpp b/Source/WebCore/platform/graphics/android/ShaderProgram.cpp index cc9c810..2a6a488 100644 --- a/Source/WebCore/platform/graphics/android/ShaderProgram.cpp +++ b/Source/WebCore/platform/graphics/android/ShaderProgram.cpp @@ -195,6 +195,8 @@ GLuint ShaderProgram::createProgram(const char* pVertexSource, const char* pFrag ShaderProgram::ShaderProgram() : m_blendingEnabled(false) , m_contrast(1) + , m_alphaLayer(false) + , m_currentScale(1.0f) { init(); } @@ -286,13 +288,14 @@ void ShaderProgram::setBlendingState(bool enableBlending) // Drawing ///////////////////////////////////////////////////////////////////////////////////////// -void ShaderProgram::setViewport(SkRect& viewport) +void ShaderProgram::setViewport(SkRect& viewport, float scale) { TransformationMatrix ortho; GLUtils::setOrthographicMatrix(ortho, viewport.fLeft, viewport.fTop, viewport.fRight, viewport.fBottom, -1000, 1000); m_projectionMatrix = ortho; m_viewport = viewport; + m_currentScale = scale; } void ShaderProgram::setProjectionMatrix(SkRect& geometry, GLint projectionMatrixHandle) @@ -302,7 +305,12 @@ void ShaderProgram::setProjectionMatrix(SkRect& geometry, GLint projectionMatrix TransformationMatrix scale; scale.scale3d(geometry.width(), geometry.height(), 1.0); - TransformationMatrix total = m_projectionMatrix * translate * scale; + TransformationMatrix total; + if (!m_alphaLayer) + total = m_projectionMatrix * m_repositionMatrix * m_webViewMatrix + * translate * scale; + else + total = m_projectionMatrix * translate * scale; GLfloat projectionMatrix[16]; GLUtils::toGLMatrix(projectionMatrix, total); @@ -560,7 +568,13 @@ void ShaderProgram::drawLayerQuad(const TransformationMatrix& drawMatrix, // move the drawing depending on where the texture is on the layer modifiedDrawMatrix.translate(geometry.fLeft, geometry.fTop); modifiedDrawMatrix.scale3d(geometry.width(), geometry.height(), 1); - TransformationMatrix renderMatrix = m_projectionMatrix * modifiedDrawMatrix; + + TransformationMatrix renderMatrix; + if (!m_alphaLayer) + renderMatrix = m_projectionMatrix * m_repositionMatrix + * m_webViewMatrix * modifiedDrawMatrix; + else + renderMatrix = m_projectionMatrix * modifiedDrawMatrix; GLfloat projectionMatrix[16]; GLUtils::toGLMatrix(projectionMatrix, renderMatrix); @@ -627,6 +641,44 @@ void ShaderProgram::drawVideoLayerQuad(const TransformationMatrix& drawMatrix, glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } +void ShaderProgram::setWebViewMatrix(const float* matrix, bool alphaLayer) +{ + GLUtils::convertToTransformationMatrix(matrix, m_webViewMatrix); + m_alphaLayer = alphaLayer; +} + +void ShaderProgram::calculateAnimationDelta() +{ + // The matrix contains the scrolling info, so this rect is starting from + // the m_viewport. + // So we just need to map the webview's visible rect using the matrix, + // calculate the difference b/t transformed rect and the webViewRect, + // then we can get the delta x , y caused by the animation. + // Note that the Y is for reporting back to GL viewport, so it is inverted. + // When it is alpha animation, then we rely on the framework implementation + // such that there is no matrix applied in native webkit. + if (!m_alphaLayer) { + FloatRect rect(m_viewport.fLeft * m_currentScale, + m_viewport.fTop * m_currentScale, + m_webViewRect.width(), + m_webViewRect.height()); + rect = m_webViewMatrix.mapRect(rect); + m_animationDelta.setX(rect.x() - m_webViewRect.x() ); + m_animationDelta.setY(rect.y() + rect.height() - m_webViewRect.y() + - m_webViewRect.height() - m_titleBarHeight); + + m_repositionMatrix.makeIdentity(); + m_repositionMatrix.translate3d(-m_webViewRect.x(), -m_webViewRect.y() - m_titleBarHeight, 0); + m_repositionMatrix.translate3d(m_viewport.fLeft * m_currentScale, m_viewport.fTop * m_currentScale, 0); + m_repositionMatrix.translate3d(-m_animationDelta.x(), -m_animationDelta.y(), 0); + } else { + m_animationDelta.setX(0); + m_animationDelta.setY(0); + m_repositionMatrix.makeIdentity(); + } + +} + } // namespace WebCore #endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/android/ShaderProgram.h b/Source/WebCore/platform/graphics/android/ShaderProgram.h index b309872..9ab7a46 100644 --- a/Source/WebCore/platform/graphics/android/ShaderProgram.h +++ b/Source/WebCore/platform/graphics/android/ShaderProgram.h @@ -36,7 +36,7 @@ public: int program() { return m_program; } // Drawing - void setViewport(SkRect& viewport); + void setViewport(SkRect& viewport, float scale); float zValue(const TransformationMatrix& drawMatrix, float w, float h); // For drawQuad and drawLayerQuad, they can handle 3 cases for now: @@ -88,6 +88,18 @@ public: contrast = MAX_CONTRAST; m_contrast = contrast; } + void setWebViewMatrix(const float* matrix, bool alphaLayer); + + // This delta is the delta from the layout pos and the current animation pos. + // Basically, in terms of layout, the webview is still in the original layout + // pos, as without animation. Such that the viewport and visible rect etc are + // still in that pos, too, except the clipping info. + // Our rendering approach is after applying all the matrix, webView is + // rendered as if it was at the original layout pos, but then offset the + // glViewport to match the animation. + void calculateAnimationDelta(); + int getAnimationDeltaX() { return m_animationDelta.x(); } + int getAnimationDeltaY() { return m_animationDelta.y(); } private: GLuint loadShader(GLenum shaderType, const char* pSource); @@ -158,6 +170,22 @@ private: GLint m_hPosition; GLint m_hPositionInverted; GLint m_hVideoPosition; + + bool m_alphaLayer; + TransformationMatrix m_webViewMatrix; + float m_currentScale; + + // After the webViewTranform, we need to reposition the rect to match our viewport. + // Basically, the webViewTransformMatrix should apply on the screen resolution. + // So we start by doing the scale and translate to get each tile into screen coordinates. + // After applying the webViewTransformMatrix, b/c the way it currently set up + // for scroll and titlebar, we need to offset both of them. + // Finally, map everything back to (-1, 1) by using the m_projectionMatrix. + // TODO: Given that m_webViewMatrix contains most of the tranformation + // information, we should be able to get rid of some parameter we got from + // Java side and simplify our code. + TransformationMatrix m_repositionMatrix; + IntPoint m_animationDelta; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/TexturesGenerator.cpp b/Source/WebCore/platform/graphics/android/TexturesGenerator.cpp index 0820688..bccb99b 100644 --- a/Source/WebCore/platform/graphics/android/TexturesGenerator.cpp +++ b/Source/WebCore/platform/graphics/android/TexturesGenerator.cpp @@ -184,11 +184,10 @@ bool TexturesGenerator::threadLoop() m_currentOperation->run(); } + QueuedOperation* oldOperation = m_currentOperation; mRequestedOperationsLock.lock(); - if (m_currentOperation) { - delete m_currentOperation; + if (m_currentOperation) m_currentOperation = 0; - } if (!mRequestedOperations.size()) stop = true; if (m_waitForCompletion) { @@ -197,7 +196,8 @@ bool TexturesGenerator::threadLoop() mRequestedOperationsCond.signal(); } mRequestedOperationsLock.unlock(); - + if (oldOperation) + delete oldOperation; // delete outside lock } XLOG("threadLoop empty"); diff --git a/Source/WebCore/platform/graphics/android/TilePainter.h b/Source/WebCore/platform/graphics/android/TilePainter.h index 91030cb..4d0f5dc 100644 --- a/Source/WebCore/platform/graphics/android/TilePainter.h +++ b/Source/WebCore/platform/graphics/android/TilePainter.h @@ -27,6 +27,7 @@ #define TilePainter_h #include "TransformationMatrix.h" +#include "SkRefCnt.h" class SkCanvas; @@ -41,6 +42,15 @@ public: virtual const TransformationMatrix* transform() { return 0; } }; +class SurfacePainter : public SkRefCnt { +public: + virtual ~SurfacePainter() { } + virtual const TransformationMatrix* transform() { return 0; } + virtual float opacity() { return 1.0; } + enum SurfaceType { PaintedSurface, ImageSurface }; + virtual SurfaceType type() { return PaintedSurface; } +}; + } #endif // TilePainter_h diff --git a/Source/WebCore/platform/graphics/android/TiledPage.cpp b/Source/WebCore/platform/graphics/android/TiledPage.cpp index e33d39a..31a0593 100644 --- a/Source/WebCore/platform/graphics/android/TiledPage.cpp +++ b/Source/WebCore/platform/graphics/android/TiledPage.cpp @@ -242,9 +242,6 @@ void TiledPage::prepare(bool goingDown, bool goingLeft, const SkIRect& tileBound int nbTilesWidth = tileBounds.width(); int nbTilesHeight = tileBounds.height(); - int lastTileX = tileBounds.fRight - 1; - int lastTileY = tileBounds.fBottom - 1; - // Expand number of tiles to allow tiles outside of viewport to be prepared for // smoother scrolling. int nTilesToPrepare = nbTilesWidth * nbTilesHeight; @@ -256,21 +253,31 @@ void TiledPage::prepare(bool goingDown, bool goingLeft, const SkIRect& tileBound int expandY = m_glWebViewState->expandedTileBoundsY(); firstTileX -= expandX; - lastTileX += expandX; nbTilesWidth += expandX * 2; firstTileY -= expandY; - lastTileY += expandY; nbTilesHeight += expandY * 2; } - // crop the prepared region to the contents of the base layer - float maxWidthTiles = m_glWebViewState->baseContentWidth() * m_scale / TilesManager::tileWidth(); - float maxHeightTiles = m_glWebViewState->baseContentHeight() * m_scale / TilesManager::tileHeight(); - firstTileX = std::max(0, firstTileX); - firstTileY = std::max(0, firstTileY); - lastTileX = std::min(lastTileX, static_cast<int>(ceilf(maxWidthTiles)) - 1); - lastTileY = std::min(lastTileY, static_cast<int>(ceilf(maxHeightTiles)) - 1); + // crop the tile bounds in each dimension to the larger of the base layer or viewport + float maxBaseX = m_glWebViewState->baseContentWidth() * m_scale / TilesManager::tileWidth(); + float maxBaseY = m_glWebViewState->baseContentHeight() * m_scale / TilesManager::tileHeight(); + int maxX = std::max(static_cast<int>(ceilf(maxBaseX)), + m_glWebViewState->viewportTileBounds().width()); + int maxY = std::max(static_cast<int>(ceilf(maxBaseY)), + m_glWebViewState->viewportTileBounds().height()); + + // adjust perimeter to not go outside cropped region + if (firstTileX < 0) { + nbTilesWidth += firstTileX; + firstTileX = 0; + } + if (firstTileY < 0) { + nbTilesHeight += firstTileY; + firstTileY = 0; + } + nbTilesWidth = std::min(nbTilesWidth, maxX - firstTileX); + nbTilesHeight = std::min(nbTilesHeight, maxY - firstTileY); // check against corrupted scale values giving bad height/width (use float to avoid overflow) float numTiles = static_cast<float>(nbTilesHeight) * static_cast<float>(nbTilesWidth); diff --git a/Source/WebCore/platform/graphics/android/TiledTexture.cpp b/Source/WebCore/platform/graphics/android/TiledTexture.cpp index 5538e1b..d538416 100644 --- a/Source/WebCore/platform/graphics/android/TiledTexture.cpp +++ b/Source/WebCore/platform/graphics/android/TiledTexture.cpp @@ -204,6 +204,7 @@ void TiledTexture::prepareTile(bool repaint, int x, int y) if (tile->isDirty() || !tile->frontTexture()) tile->reserveTexture(); + bool hasPicture = m_paintingPicture != 0; // safely read on UI thread, since only UI thread writes if (tile->backTexture() && tile->isDirty() && !tile->isRepaintPending() && hasPicture) { PaintTileOperation *operation = new PaintTileOperation(tile, m_surface); @@ -223,12 +224,26 @@ BaseTile* TiledTexture::getTile(int x, int y) int TiledTexture::nbTextures(IntRect& area, float scale) { - IntRect computedTilesArea = computeTilesArea(area, scale); - return computedTilesArea.width() * computedTilesArea.height(); + IntRect tileBounds = computeTilesArea(area, scale); + int numberTextures = tileBounds.width() * tileBounds.height(); + + // add the number of dirty tiles in the bounds, as they take up double + // textures for double buffering + for (unsigned int i = 0; i <m_tiles.size(); i++) { + BaseTile* tile = m_tiles[i]; + if (tile->isDirty() + && tile->x() >= tileBounds.x() && tile->x() <= tileBounds.maxX() + && tile->y() >= tileBounds.y() && tile->y() <= tileBounds.maxY()) + numberTextures++; + } + return numberTextures; } bool TiledTexture::draw() { + if (!m_surface) + return true; + XLOG("TT %p draw", this); #ifdef DEBUG @@ -257,8 +272,8 @@ bool TiledTexture::draw() rect.fTop = tile->y() * tileHeight; rect.fRight = rect.fLeft + tileWidth; rect.fBottom = rect.fTop + tileHeight; - XLOG("- [%d], { painter %x vs %x }, tile %x %d,%d at scale %.2f vs %.2f [ready: %d] dirty: %d", - i, this, tile->painter(), tile, tile->x(), tile->y(), + XLOG("- [%d], { painter %x vs %x }, tile %x (layer tile: %d) %d,%d at scale %.2f vs %.2f [ready: %d] dirty: %d", + i, this, tile->painter(), tile, tile->isLayerTile(), tile->x(), tile->y(), tile->scale(), m_scale, tile->isTileReady(), tile->isDirty()); tile->draw(m_surface->opacity(), rect, m_scale); #ifdef DEBUG @@ -283,7 +298,7 @@ bool TiledTexture::paint(BaseTile* tile, SkCanvas* canvas, unsigned int* picture return false; } - XLOG("TT %p painting with picture %p", this, picture); + XLOG("TT %p painting tile %d, %d with picture %p", this, tile->x(), tile->y(), picture); canvas->drawPicture(*picture); @@ -294,6 +309,8 @@ bool TiledTexture::paint(BaseTile* tile, SkCanvas* canvas, unsigned int* picture const TransformationMatrix* TiledTexture::transform() { + if (!m_surface) + return 0; return m_surface->transform(); } @@ -323,7 +340,7 @@ bool TiledTexture::owns(BaseTileTexture* texture) return false; } -DualTiledTexture::DualTiledTexture(PaintedSurface* surface) +DualTiledTexture::DualTiledTexture(SurfacePainter* surface) { m_textureA = new TiledTexture(surface); m_textureB = new TiledTexture(surface); @@ -364,6 +381,7 @@ void DualTiledTexture::prepare(GLWebViewState* state, float scale, bool repaint, if (m_zooming && m_zoomUpdateTime < WTF::currentTime()) { m_backTexture->prepare(state, m_futureScale, repaint, startFastSwap, visibleArea); if (m_backTexture->ready()) { + m_backTexture->swapTiles(); swap(); m_zooming = false; } diff --git a/Source/WebCore/platform/graphics/android/TiledTexture.h b/Source/WebCore/platform/graphics/android/TiledTexture.h index b761880..444ab14 100644 --- a/Source/WebCore/platform/graphics/android/TiledTexture.h +++ b/Source/WebCore/platform/graphics/android/TiledTexture.h @@ -39,11 +39,9 @@ class SkCanvas; namespace WebCore { -class PaintedSurface; - class TiledTexture : public TilePainter { public: - TiledTexture(PaintedSurface* surface) + TiledTexture(SurfacePainter* surface) : m_paintingPicture(0) , m_surface(surface) , m_prevTileX(0) @@ -82,8 +80,6 @@ public: float scale() { return m_scale; } bool ready(); - PaintedSurface* surface() { return m_surface; } - int nbTextures(IntRect& area, float scale); private: @@ -95,7 +91,7 @@ private: android::Mutex m_paintingPictureSync; SkPicture* m_paintingPicture; - PaintedSurface* m_surface; + SurfacePainter* m_surface; Vector<BaseTile*> m_tiles; // tile coordinates in viewport, set in prepare() @@ -112,7 +108,7 @@ private: class DualTiledTexture { public: - DualTiledTexture(PaintedSurface* surface); + DualTiledTexture(SurfacePainter* surface); ~DualTiledTexture(); void prepare(GLWebViewState* state, float scale, bool repaint, bool startFastSwap, IntRect& area); diff --git a/Source/WebCore/platform/graphics/android/TilesManager.cpp b/Source/WebCore/platform/graphics/android/TilesManager.cpp index 219435d..30bd8d0 100644 --- a/Source/WebCore/platform/graphics/android/TilesManager.cpp +++ b/Source/WebCore/platform/graphics/android/TilesManager.cpp @@ -189,6 +189,23 @@ void TilesManager::deallocateTexturesVector(unsigned long long sparedDrawCount, dealloc, max, maxLayer); } +void TilesManager::gatherTexturesNumbers(int* nbTextures, int* nbAllocatedTextures, + int* nbLayerTextures, int* nbAllocatedLayerTextures) +{ + *nbTextures = m_textures.size(); + for (unsigned int i = 0; i < m_textures.size(); i++) { + BaseTileTexture* texture = m_textures[i]; + if (texture->m_ownTextureId) + *nbAllocatedTextures += 1; + } + *nbLayerTextures = m_tilesTextures.size(); + for (unsigned int i = 0; i < m_tilesTextures.size(); i++) { + BaseTileTexture* texture = m_tilesTextures[i]; + if (texture->m_ownTextureId) + *nbAllocatedLayerTextures += 1; + } +} + void TilesManager::printTextures() { #ifdef DEBUG diff --git a/Source/WebCore/platform/graphics/android/TilesManager.h b/Source/WebCore/platform/graphics/android/TilesManager.h index 0c3e900..9782fbb 100644 --- a/Source/WebCore/platform/graphics/android/TilesManager.h +++ b/Source/WebCore/platform/graphics/android/TilesManager.h @@ -88,6 +88,8 @@ public: void gatherLayerTextures(); void gatherTextures(); bool layerTexturesRemain() { return m_layerTexturesRemain; } + void gatherTexturesNumbers(int* nbTextures, int* nbAllocatedTextures, + int* nbLayerTextures, int* nbAllocatedLayerTextures); BaseTileTexture* getAvailableTexture(BaseTile* owner); diff --git a/Source/WebCore/platform/graphics/android/TransferQueue.cpp b/Source/WebCore/platform/graphics/android/TransferQueue.cpp index b92edaf..b20ec7a 100644 --- a/Source/WebCore/platform/graphics/android/TransferQueue.cpp +++ b/Source/WebCore/platform/graphics/android/TransferQueue.cpp @@ -50,7 +50,7 @@ #endif // DEBUG -#define ST_BUFFER_NUMBER 4 +#define ST_BUFFER_NUMBER 6 // Set this to 1 if we would like to take the new GpuUpload approach which // relied on the glCopyTexSubImage2D instead of a glDraw call diff --git a/Source/WebCore/platform/graphics/android/TreeManager.cpp b/Source/WebCore/platform/graphics/android/TreeManager.cpp index 5fd3b7c..b7eaacf 100644 --- a/Source/WebCore/platform/graphics/android/TreeManager.cpp +++ b/Source/WebCore/platform/graphics/android/TreeManager.cpp @@ -28,6 +28,7 @@ #include "Layer.h" #include "BaseLayerAndroid.h" +#include "ScrollableLayerAndroid.h" #include "TilesManager.h" #include <cutils/log.h> @@ -87,6 +88,8 @@ void TreeManager::swap() // painting tree becomes the drawing tree XLOG("drawing tree %p", m_paintingTree); m_paintingTree->setIsDrawing(true); + if (m_paintingTree->countChildren()) + static_cast<LayerAndroid*>(m_paintingTree->getChild(0))->initAnimations(); if (m_queuedTree) { // start painting with the queued tree @@ -132,6 +135,10 @@ void TreeManager::clearTrees() // or start painting it if we aren't void TreeManager::updateWithTree(Layer* newTree, bool brandNew) { + XLOG("updateWithTree - %p, has children %d, has animations %d", + newTree, newTree && newTree->countChildren(), + newTree && newTree->countChildren() + ? static_cast<LayerAndroid*>(newTree->getChild(0))->hasAnimations() : 0); // can't have a queued tree unless have a painting tree too ASSERT(m_paintingTree || !m_queuedTree); @@ -143,10 +150,6 @@ void TreeManager::updateWithTree(Layer* newTree, bool brandNew) if (!newTree || brandNew) { clearTrees(); if (brandNew) { - m_animationOffset = 0; - m_isAnimating = false; - m_lastFrameTime = WTF::currentTime(); - m_paintingTree = newTree; m_paintingTree->setIsPainting(m_drawingTree); } @@ -159,6 +162,11 @@ void TreeManager::updateWithTree(Layer* newTree, bool brandNew) // have a queued tree, copy over invals so the regions are // eventually repainted m_queuedTree->mergeInvalsInto(newTree); + + XLOG("DISCARDING tree - %p, has children %d, has animations %d", + newTree, newTree && newTree->countChildren(), + newTree && newTree->countChildren() + ? static_cast<LayerAndroid*>(newTree->getChild(0))->hasAnimations() : 0); } SkSafeUnref(m_queuedTree); m_queuedTree = newTree; @@ -170,9 +178,26 @@ void TreeManager::updateWithTree(Layer* newTree, bool brandNew) m_paintingTree->setIsPainting(m_drawingTree); } +void TreeManager::updateScrollableLayerInTree(Layer* tree, int layerId, int x, int y) +{ + LayerAndroid* layer; + if (tree && tree->countChildren()) { + layer = static_cast<LayerAndroid*>(tree->getChild(0))->findById(layerId); + if (layer && layer->contentIsScrollable()) + static_cast<ScrollableLayerAndroid*>(layer)->scrollTo(x, y); + } +} + +void TreeManager::updateScrollableLayer(int layerId, int x, int y) +{ + updateScrollableLayerInTree(m_queuedTree, layerId, x, y); + updateScrollableLayerInTree(m_paintingTree, layerId, x, y); + updateScrollableLayerInTree(m_drawingTree, layerId, x, y); +} + bool TreeManager::drawGL(double currentTime, IntRect& viewRect, SkRect& visibleRect, float scale, - bool enterFastSwapMode, bool* buffersSwappedPtr, + bool enterFastSwapMode, bool* treesSwappedPtr, bool* newTreeHasAnimPtr, TexturesResult* texturesResultPtr) { m_fastSwapMode |= enterFastSwapMode; @@ -183,19 +208,28 @@ bool TreeManager::drawGL(double currentTime, IntRect& viewRect, bool ret = false; bool didTreeSwap = false; if (m_paintingTree) { + XLOG("preparing painting tree %p", m_paintingTree); + + LayerAndroid* laTree = 0; + if (m_paintingTree->countChildren()) { + laTree = static_cast<LayerAndroid*>(m_paintingTree->getChild(0)); + ret |= laTree->evaluateAnimations(currentTime); + } + ret |= m_paintingTree->prepare(currentTime, viewRect, visibleRect, scale); - if (m_paintingTree->countChildren()) { - LayerAndroid* laTree = static_cast<LayerAndroid*>(m_paintingTree->getChild(0)); + if (laTree) laTree->computeTexturesAmount(texturesResultPtr); - } + if (/*!m_fastSwapMode && */ m_paintingTree->isReady()) { XLOG("have painting tree %p ready, swapping!", m_paintingTree); didTreeSwap = true; swap(); - if (buffersSwappedPtr) - *buffersSwappedPtr = true; + if (treesSwappedPtr) + *treesSwappedPtr = true; + if (laTree && newTreeHasAnimPtr) + *newTreeHasAnimPtr = laTree->hasAnimations(); } } else if (m_drawingTree) { XLOG("preparing drawing tree %p", m_drawingTree); @@ -207,17 +241,11 @@ bool TreeManager::drawGL(double currentTime, IntRect& viewRect, } } - if (!m_isAnimating) { - m_animationOffset += currentTime - m_lastFrameTime; -#ifdef ANIM_DEBUG - XLOGC("adding to %f", m_animationOffset); -#endif - } if (m_drawingTree) { bool drawingReady = didTreeSwap || m_drawingTree->isReady(); - if (drawingReady || m_fastSwapMode) + if (didTreeSwap || m_fastSwapMode || (drawingReady && !m_paintingTree)) m_drawingTree->swapTiles(); if (drawingReady) { @@ -229,18 +257,8 @@ bool TreeManager::drawGL(double currentTime, IntRect& viewRect, } if (m_drawingTree->countChildren()) { -#ifdef ANIM_DEBUG - XLOGC("drawing tree %p with animation time offset of %f, locked %d", - m_drawingTree, m_animationOffset, m_isAnimating); -#endif LayerAndroid* laTree = static_cast<LayerAndroid*>(m_drawingTree->getChild(0)); - m_isAnimating = laTree->evaluateAnimations(currentTime - m_animationOffset); - if (!m_isAnimating) - m_animationOffset = 0; - ret |= m_isAnimating; - } else if (!m_paintingTree) { - m_animationOffset = 0; - m_isAnimating = false; + ret |= laTree->evaluateAnimations(currentTime); } XLOG("drawing tree %p", m_drawingTree); ret |= m_drawingTree->drawGL(viewRect, visibleRect, scale); @@ -250,8 +268,6 @@ bool TreeManager::drawGL(double currentTime, IntRect& viewRect, m_paintingTree->state()->drawBackground(defaultBackground); } - m_lastFrameTime = currentTime; - if (m_paintingTree) { XLOG("still have painting tree %p", m_paintingTree); return true; diff --git a/Source/WebCore/platform/graphics/android/TreeManager.h b/Source/WebCore/platform/graphics/android/TreeManager.h index 09b1bd9..83d5300 100644 --- a/Source/WebCore/platform/graphics/android/TreeManager.h +++ b/Source/WebCore/platform/graphics/android/TreeManager.h @@ -28,6 +28,7 @@ #include "TestExport.h" #include <utils/threads.h> +#include "PerformanceMonitor.h" class Layer; class SkRect; @@ -46,9 +47,11 @@ public: void updateWithTree(Layer* tree, bool brandNew); + void updateScrollableLayer(int layerId, int x, int y); + bool drawGL(double currentTime, IntRect& viewRect, SkRect& visibleRect, float scale, - bool enterFastSwapMode, bool* buffersSwappedPtr, + bool enterFastSwapMode, bool* treesSwappedPtr, bool* newTreeHasAnimPtr, TexturesResult* texturesResultPtr); void drawCanvas(SkCanvas* canvas, bool drawLayers); @@ -60,6 +63,8 @@ public: int baseContentHeight(); private: + static void updateScrollableLayerInTree(Layer* tree, int layerId, int x, int y); + void swap(); void clearTrees(); @@ -70,10 +75,7 @@ private: Layer* m_queuedTree; bool m_fastSwapMode; - - double m_animationOffset; - double m_lastFrameTime; - bool m_isAnimating; + PerformanceMonitor m_perf; }; } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderBlockLineLayout.cpp b/Source/WebCore/rendering/RenderBlockLineLayout.cpp index d4e2aa3..df20063 100644 --- a/Source/WebCore/rendering/RenderBlockLineLayout.cpp +++ b/Source/WebCore/rendering/RenderBlockLineLayout.cpp @@ -812,7 +812,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica else { #ifdef ANDROID_LAYOUT // ignore text wrap for textField or menuList - if (doTextWrap && (o->isTextField() || o->isMenuList() || o->isFloating())) + if (doTextWrap && (o->isTextField() || o->isMenuList())) doTextWrap = false; #endif if (o->isFloating()) diff --git a/Source/WebCore/rendering/RenderBox.cpp b/Source/WebCore/rendering/RenderBox.cpp index 80d5699..fb1dd2c 100644 --- a/Source/WebCore/rendering/RenderBox.cpp +++ b/Source/WebCore/rendering/RenderBox.cpp @@ -1562,6 +1562,13 @@ void RenderBox::computeLogicalWidth() // https://bugs.webkit.org/show_bug.cgi?id=46418 if (hasOverrideSize() && parent()->style()->boxOrient() == HORIZONTAL && parent()->isFlexibleBox() && parent()->isFlexingChildren()) { +#if PLATFORM(ANDROID) + // Strangely, the slider is get overrided as width 0 on youtube.com + // The wrong width will cause the touch hit test for the slider failed. + // This WAR should be safe since it is only targeted to slider. + // TODO: root cause this and see if any webkit update fix this. + if (!(isSlider() && overrideSize() == 0)) +#endif setLogicalWidth(overrideSize()); return; } diff --git a/Source/WebCore/rendering/RenderLayer.cpp b/Source/WebCore/rendering/RenderLayer.cpp index 904b1b2..cdc4c05 100644 --- a/Source/WebCore/rendering/RenderLayer.cpp +++ b/Source/WebCore/rendering/RenderLayer.cpp @@ -1419,8 +1419,15 @@ void RenderLayer::scrollTo(int x, int y) } // Just schedule a full repaint of our object. +#if ENABLE(ANDROID_OVERFLOW_SCROLL) + // On android, scrollable areas are put on composited layers, so we + // do not need to repaint simply because we are scrolling + if (view && !hasOverflowScroll()) + renderer()->repaintUsingContainer(repaintContainer, rectForRepaint); +#else if (view) renderer()->repaintUsingContainer(repaintContainer, rectForRepaint); +#endif // Schedule the scroll DOM event. renderer()->node()->document()->eventQueue()->enqueueOrDispatchScrollEvent(renderer()->node(), EventQueue::ScrollEventElementTarget); diff --git a/Source/WebCore/rendering/RenderLayerCompositor.cpp b/Source/WebCore/rendering/RenderLayerCompositor.cpp index 5827636..1ef3b77 100644 --- a/Source/WebCore/rendering/RenderLayerCompositor.cpp +++ b/Source/WebCore/rendering/RenderLayerCompositor.cpp @@ -1576,7 +1576,12 @@ bool RenderLayerCompositor::requiresCompositingForAnimation(RenderObject* render return false; if (AnimationController* animController = renderer->animation()) { +#if PLATFORM(ANDROID) + // android renders an opacity animation much faster if it's composited + return (animController->isRunningAnimationOnRenderer(renderer, CSSPropertyOpacity)) +#else return (animController->isRunningAnimationOnRenderer(renderer, CSSPropertyOpacity) && inCompositingMode()) +#endif || animController->isRunningAnimationOnRenderer(renderer, CSSPropertyWebkitTransform); } return false; |