summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Source/WebCore/Android.mk2
-rw-r--r--Source/WebCore/loader/cache/CachedImage.cpp2
-rw-r--r--Source/WebCore/loader/cache/CachedImage.h5
-rw-r--r--Source/WebCore/loader/cache/CachedResource.cpp2
-rw-r--r--Source/WebCore/loader/cache/CachedResource.h1
-rw-r--r--Source/WebCore/loader/cache/CachedResourceLoader.cpp30
-rw-r--r--Source/WebCore/platform/graphics/android/AndroidAnimation.cpp66
-rw-r--r--Source/WebCore/platform/graphics/android/AndroidAnimation.h15
-rw-r--r--Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp238
-rw-r--r--Source/WebCore/platform/graphics/android/BaseLayerAndroid.h21
-rw-r--r--Source/WebCore/platform/graphics/android/BaseTile.cpp3
-rw-r--r--Source/WebCore/platform/graphics/android/ClassTracker.cpp21
-rw-r--r--Source/WebCore/platform/graphics/android/FontAndroid.cpp4
-rw-r--r--Source/WebCore/platform/graphics/android/GLUtils.cpp9
-rw-r--r--Source/WebCore/platform/graphics/android/GLUtils.h1
-rw-r--r--Source/WebCore/platform/graphics/android/GLWebViewState.cpp251
-rw-r--r--Source/WebCore/platform/graphics/android/GLWebViewState.h33
-rw-r--r--Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp9
-rw-r--r--Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp45
-rw-r--r--Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h2
-rw-r--r--Source/WebCore/platform/graphics/android/ImageTexture.cpp214
-rw-r--r--Source/WebCore/platform/graphics/android/ImageTexture.h70
-rw-r--r--Source/WebCore/platform/graphics/android/ImagesManager.cpp108
-rw-r--r--Source/WebCore/platform/graphics/android/ImagesManager.h16
-rw-r--r--Source/WebCore/platform/graphics/android/Layer.cpp9
-rw-r--r--Source/WebCore/platform/graphics/android/Layer.h51
-rw-r--r--Source/WebCore/platform/graphics/android/LayerAndroid.cpp246
-rw-r--r--Source/WebCore/platform/graphics/android/LayerAndroid.h50
-rw-r--r--Source/WebCore/platform/graphics/android/MediaLayer.cpp7
-rw-r--r--Source/WebCore/platform/graphics/android/MediaLayer.h2
-rw-r--r--Source/WebCore/platform/graphics/android/PaintTileOperation.cpp18
-rw-r--r--Source/WebCore/platform/graphics/android/PaintTileOperation.h10
-rw-r--r--Source/WebCore/platform/graphics/android/PaintedSurface.cpp117
-rw-r--r--Source/WebCore/platform/graphics/android/PaintedSurface.h30
-rw-r--r--Source/WebCore/platform/graphics/android/QueuedOperation.h4
-rw-r--r--Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp3
-rw-r--r--Source/WebCore/platform/graphics/android/ShaderProgram.cpp61
-rw-r--r--Source/WebCore/platform/graphics/android/ShaderProgram.h30
-rw-r--r--Source/WebCore/platform/graphics/android/TestExport.h32
-rw-r--r--Source/WebCore/platform/graphics/android/TexturesGenerator.cpp8
-rw-r--r--Source/WebCore/platform/graphics/android/TilePainter.h10
-rw-r--r--Source/WebCore/platform/graphics/android/TiledPage.cpp92
-rw-r--r--Source/WebCore/platform/graphics/android/TiledPage.h19
-rw-r--r--Source/WebCore/platform/graphics/android/TiledTexture.cpp139
-rw-r--r--Source/WebCore/platform/graphics/android/TiledTexture.h36
-rw-r--r--Source/WebCore/platform/graphics/android/TilesManager.cpp113
-rw-r--r--Source/WebCore/platform/graphics/android/TilesManager.h17
-rw-r--r--Source/WebCore/platform/graphics/android/TransferQueue.cpp16
-rw-r--r--Source/WebCore/platform/graphics/android/TreeManager.cpp331
-rw-r--r--Source/WebCore/platform/graphics/android/TreeManager.h (renamed from Source/WebCore/platform/graphics/android/UpdateManager.h)74
-rw-r--r--Source/WebCore/platform/graphics/android/UpdateManager.cpp120
-rw-r--r--Source/WebCore/platform/graphics/android/VideoLayerAndroid.cpp4
-rw-r--r--Source/WebCore/platform/graphics/android/VideoLayerAndroid.h2
-rw-r--r--Source/WebCore/rendering/RenderBlockLineLayout.cpp2
-rw-r--r--Source/WebCore/rendering/RenderBox.cpp7
-rw-r--r--Source/WebCore/rendering/RenderHTMLCanvas.cpp6
-rw-r--r--Source/WebCore/rendering/RenderLayer.cpp7
-rw-r--r--Source/WebCore/rendering/RenderLayerCompositor.cpp28
-rw-r--r--Source/WebCore/rendering/svg/SVGInlineTextBox.cpp20
-rw-r--r--Source/WebCore/tests/Android.mk49
-rw-r--r--Source/WebCore/tests/TreeManager_test.cpp407
-rw-r--r--Source/WebKit/android/WebCoreSupport/CacheResult.cpp11
-rw-r--r--Source/WebKit/android/jni/CacheManager.cpp1
-rw-r--r--Source/WebKit/android/jni/ViewStateSerializer.cpp24
-rw-r--r--Source/WebKit/android/jni/WebHistory.cpp2
-rw-r--r--Source/WebKit/android/jni/WebViewCore.cpp41
-rw-r--r--Source/WebKit/android/jni/WebViewCore.h1
-rw-r--r--Source/WebKit/android/nav/CacheBuilder.cpp3
-rw-r--r--Source/WebKit/android/nav/WebView.cpp215
69 files changed, 2421 insertions, 1222 deletions
diff --git a/Source/WebCore/Android.mk b/Source/WebCore/Android.mk
index a516f48..6542931 100644
--- a/Source/WebCore/Android.mk
+++ b/Source/WebCore/Android.mk
@@ -680,7 +680,7 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \
platform/graphics/android/TiledPage.cpp \
platform/graphics/android/TiledTexture.cpp \
platform/graphics/android/TransferQueue.cpp \
- platform/graphics/android/UpdateManager.cpp \
+ platform/graphics/android/TreeManager.cpp \
platform/graphics/android/VerticalTextMap.cpp \
platform/graphics/android/VideoLayerAndroid.cpp \
platform/graphics/android/VideoLayerManager.cpp \
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 0e6f64f..7ec2d78 100644
--- a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp
+++ b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp
@@ -66,8 +66,7 @@ using namespace android;
BaseLayerAndroid::BaseLayerAndroid()
#if USE(ACCELERATED_COMPOSITING)
- : m_glWebViewState(0)
- , m_color(Color::white)
+ : m_color(Color::white)
, m_scrollState(NotScrolling)
#endif
{
@@ -123,8 +122,8 @@ void BaseLayerAndroid::prefetchBasePicture(SkRect& viewport, float currentScale,
/ TilesManager::instance()->tileWidth();
float invTileHeight = (prefetchScale)
/ TilesManager::instance()->tileHeight();
- bool goingDown = m_glWebViewState->goingDown();
- bool goingLeft = m_glWebViewState->goingLeft();
+ bool goingDown = m_state->goingDown();
+ bool goingLeft = m_state->goingLeft();
XLOG("fetch rect %f %f %f %f, scale %f",
@@ -150,21 +149,82 @@ void BaseLayerAndroid::prefetchBasePicture(SkRect& viewport, float currentScale,
prefetchTiledPage->prepare(goingDown, goingLeft, bounds,
TiledPage::ExpandedBounds);
prefetchTiledPage->swapBuffersIfReady(bounds,
- prefetchScale,
- TiledPage::SwapWhateverIsReady);
+ prefetchScale);
if (draw)
- prefetchTiledPage->draw(PREFETCH_OPACITY, bounds);
+ prefetchTiledPage->prepareForDrawGL(PREFETCH_OPACITY, bounds);
}
-bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale,
- double currentTime, bool* buffersSwappedPtr)
+bool BaseLayerAndroid::isReady()
{
- ZoomManager* zoomManager = m_glWebViewState->zoomManager();
+ ZoomManager* zoomManager = m_state->zoomManager();
+ if (ZoomManager::kNoScaleRequest != zoomManager->scaleRequestState()) {
+ XLOG("base layer not ready, still zooming");
+ return false; // still zooming
+ }
+
+ if (!m_state->frontPage()->isReady(m_state->preZoomBounds())) {
+ XLOG("base layer not ready, front page not done painting");
+ return false;
+ }
+
+ LayerAndroid* compositedRoot = static_cast<LayerAndroid*>(getChild(0));
+ if (compositedRoot) {
+ XLOG("base layer is ready, how about children?");
+ return compositedRoot->isReady();
+ }
+
+ return true;
+}
+
+void BaseLayerAndroid::swapTiles()
+{
+ if (countChildren())
+ getChild(0)->swapTiles(); // TODO: move to parent impl
+
+ m_state->frontPage()->swapBuffersIfReady(m_state->preZoomBounds(),
+ m_state->zoomManager()->currentScale());
+
+ m_state->backPage()->swapBuffersIfReady(m_state->preZoomBounds(),
+ m_state->zoomManager()->currentScale());
+}
+
+void BaseLayerAndroid::setIsDrawing(bool isDrawing)
+{
+ if (countChildren())
+ getChild(0)->setIsDrawing(isDrawing); // TODO: move to parent impl
+}
+
+void BaseLayerAndroid::setIsPainting(Layer* drawingTree)
+{
+ XLOG("BLA %p painting, dirty %d", this, isDirty());
+ if (drawingTree)
+ drawingTree = drawingTree->getChild(0);
+
+ if (countChildren())
+ getChild(0)->setIsPainting(drawingTree); // TODO: move to parent impl
+
+ m_state->invalRegion(m_dirtyRegion);
+ m_dirtyRegion.setEmpty();
+}
+
+void BaseLayerAndroid::mergeInvalsInto(Layer* replacementTree)
+{
+ XLOG("merging invals (empty=%d) from BLA %p to %p", m_dirtyRegion.isEmpty(), this, replacementTree);
+ if (countChildren() && replacementTree->countChildren())
+ getChild(0)->mergeInvalsInto(replacementTree->getChild(0));
- bool goingDown = m_glWebViewState->goingDown();
- bool goingLeft = m_glWebViewState->goingLeft();
+ replacementTree->markAsDirty(m_dirtyRegion);
+}
+
+bool BaseLayerAndroid::prepareBasePictureInGL(SkRect& viewport, float scale,
+ double currentTime)
+{
+ ZoomManager* zoomManager = m_state->zoomManager();
+
+ bool goingDown = m_state->goingDown();
+ bool goingLeft = m_state->goingLeft();
- const SkIRect& viewportTileBounds = m_glWebViewState->viewportTileBounds();
+ const SkIRect& viewportTileBounds = m_state->viewportTileBounds();
XLOG("drawBasePicture, TX: %d, TY: %d scale %.2f", viewportTileBounds.fLeft,
viewportTileBounds.fTop, scale);
@@ -172,15 +232,14 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale,
bool prepareNextTiledPage = zoomManager->needPrepareNextTiledPage();
// Display the current page
- TiledPage* tiledPage = m_glWebViewState->frontPage();
- TiledPage* nextTiledPage = m_glWebViewState->backPage();
+ TiledPage* tiledPage = m_state->frontPage();
+ TiledPage* nextTiledPage = m_state->backPage();
tiledPage->setScale(zoomManager->currentScale());
// Let's prepare the page if needed so that it will start painting
if (prepareNextTiledPage) {
nextTiledPage->setScale(scale);
- m_glWebViewState->setFutureViewport(viewportTileBounds);
- m_glWebViewState->lockBaseLayerUpdate();
+ m_state->setFutureViewport(viewportTileBounds);
// ignore dirtiness return value since while zooming we repaint regardless
nextTiledPage->updateTileDirtiness(viewportTileBounds);
@@ -194,8 +253,7 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale,
// If we fired a request, let's check if it's ready to use
if (zoomManager->didFireRequest()) {
if (nextTiledPage->swapBuffersIfReady(viewportTileBounds,
- zoomManager->futureScale(),
- TiledPage::SwapWholePage))
+ zoomManager->futureScale()))
zoomManager->setReceivedRequest(); // transition to received request state
}
@@ -208,74 +266,31 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale,
float nextTiledPageTransparency = 1;
zoomManager->processTransition(currentTime, scale, &doZoomPageSwap,
&nextTiledPageTransparency, &transparency);
- nextTiledPage->draw(nextTiledPageTransparency, viewportTileBounds);
+ nextTiledPage->prepareForDrawGL(nextTiledPageTransparency, viewportTileBounds);
}
- const SkIRect& preZoomBounds = m_glWebViewState->preZoomBounds();
+ const SkIRect& preZoomBounds = m_state->preZoomBounds();
- // update scrolling state machine by querying glwebviewstate - note that the
- // NotScrolling state is only set below
- if (m_glWebViewState->isScrolling())
- m_scrollState = Scrolling;
- else if (m_scrollState == Scrolling)
- m_scrollState = ScrollingFinishPaint;
-
- bool scrolling = m_scrollState != NotScrolling;
bool zooming = ZoomManager::kNoScaleRequest != zoomManager->scaleRequestState();
- // When we aren't zooming, we should TRY and swap tile buffers if they're
- // ready. When scrolling, we swap whatever's ready. Otherwise, buffer until
- // the entire page is ready and then swap.
- bool tilesFinished = false;
- if (!zooming) {
- TiledPage::SwapMethod swapMethod;
- if (scrolling)
- swapMethod = TiledPage::SwapWhateverIsReady;
- else
- swapMethod = TiledPage::SwapWholePage;
-
- tilesFinished = tiledPage->swapBuffersIfReady(preZoomBounds,
- zoomManager->currentScale(),
- swapMethod);
-
- if (buffersSwappedPtr && tilesFinished)
- *buffersSwappedPtr = true;
- if (tilesFinished) {
- if (m_scrollState == ScrollingFinishPaint) {
- m_scrollState = NotScrolling;
- scrolling = false;
- }
- }
- }
-
if (doZoomPageSwap) {
zoomManager->setCurrentScale(scale);
- m_glWebViewState->swapPages();
- if (buffersSwappedPtr)
- *buffersSwappedPtr = true;
+ m_state->swapPages();
}
-
- bool needsRedraw = scrolling || zooming || !tilesFinished;
-
- // if we don't expect to redraw, unlock the invals
- if (!needsRedraw)
- m_glWebViewState->unlockBaseLayerUpdate();
+ bool needsRedraw = zooming;
// if applied invals mark tiles dirty, need to redraw
needsRedraw |= tiledPage->updateTileDirtiness(preZoomBounds);
- if (needsRedraw) {
- // lock and paint what's needed unless we're zooming, since the new
- // tiles won't be relevant soon anyway
- m_glWebViewState->lockBaseLayerUpdate();
- if (!zooming)
- tiledPage->prepare(goingDown, goingLeft, preZoomBounds,
- TiledPage::ExpandedBounds);
- }
+ // paint what's needed unless we're zooming, since the new tiles won't
+ // be relevant soon anyway
+ if (!zooming)
+ tiledPage->prepare(goingDown, goingLeft, preZoomBounds,
+ TiledPage::ExpandedBounds);
- XLOG("scrolling %d, zooming %d, tilesFinished %d, needsRedraw %d",
- scrolling, zooming, tilesFinished, needsRedraw);
+ XLOG("scrolling %d, zooming %d, needsRedraw %d",
+ scrolling, zooming, needsRedraw);
// prefetch in the nextTiledPage if unused by zooming (even if not scrolling
// since we want the tiles to be ready before they're needed)
@@ -288,39 +303,74 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale,
prefetchBasePicture(viewport, scale, nextTiledPage, drawPrefetchPage);
}
- tiledPage->draw(transparency, preZoomBounds);
+ tiledPage->prepareForDrawGL(transparency, preZoomBounds);
return needsRedraw;
}
+
+void BaseLayerAndroid::drawBasePictureInGL()
+{
+ m_state->backPage()->drawGL();
+ m_state->frontPage()->drawGL();
+}
+
#endif // USE(ACCELERATED_COMPOSITING)
-bool BaseLayerAndroid::drawGL(double currentTime, LayerAndroid* compositedRoot,
- IntRect& viewRect, SkRect& visibleRect, float scale,
- bool* buffersSwappedPtr)
+void BaseLayerAndroid::updateLayerPositions(SkRect& visibleRect)
{
- bool needsRedraw = false;
-#if USE(ACCELERATED_COMPOSITING)
+ LayerAndroid* compositedRoot = static_cast<LayerAndroid*>(getChild(0));
+ TransformationMatrix ident;
+ compositedRoot->updateFixedLayersPositions(visibleRect);
+ FloatRect clip(0, 0, content()->width(), content()->height());
+ compositedRoot->updateGLPositionsAndScale(
+ ident, clip, 1, m_state->zoomManager()->layersScale());
+
+#ifdef DEBUG
+ compositedRoot->showLayer(0);
+ XLOG("We have %d layers, %d textured",
+ compositedRoot->nbLayers(),
+ compositedRoot->nbTexturedLayers());
+#endif
+}
- needsRedraw = drawBasePictureInGL(visibleRect, scale, currentTime,
- buffersSwappedPtr);
+bool BaseLayerAndroid::prepare(double currentTime, IntRect& viewRect,
+ SkRect& visibleRect, float scale)
+{
+ XLOG("preparing BLA %p", this);
- if (!needsRedraw)
- m_glWebViewState->resetFrameworkInval();
+ // base layer is simply drawn in prepare, since there is always a base layer it doesn't matter
+ bool needsRedraw = prepareBasePictureInGL(visibleRect, scale, currentTime);
+ LayerAndroid* compositedRoot = static_cast<LayerAndroid*>(getChild(0));
if (compositedRoot) {
- SkMatrix matrix;
- matrix.setTranslate(viewRect.x(), viewRect.y());
+ updateLayerPositions(visibleRect);
-#ifdef DEBUG
- compositedRoot->showLayer(0);
- XLOG("We have %d layers, %d textured",
- compositedRoot->nbLayers(),
- compositedRoot->nbTexturedLayers());
-#endif
+ XLOG("preparing BLA %p, root %p", this, compositedRoot);
+ compositedRoot->prepare();
+ }
+
+ return needsRedraw;
+}
+
+bool BaseLayerAndroid::drawGL(IntRect& viewRect, SkRect& visibleRect,
+ float scale)
+{
+ XLOG("drawing BLA %p", this);
+
+ // TODO: consider moving drawBackground outside of prepare (into tree manager)
+ m_state->drawBackground(m_color);
+ drawBasePictureInGL();
+
+ bool needsRedraw = false;
+
+#if USE(ACCELERATED_COMPOSITING)
+
+ LayerAndroid* compositedRoot = static_cast<LayerAndroid*>(getChild(0));
+ if (compositedRoot) {
+ updateLayerPositions(visibleRect);
// For now, we render layers only if the rendering mode
// is kAllTextures or kClippedTextures
- if (m_glWebViewState->layersRenderingMode() < GLWebViewState::kScrollableAndFixedLayers
- && compositedRoot->drawGL(m_glWebViewState, matrix)) {
+ if (compositedRoot->drawGL()) {
if (TilesManager::instance()->layerTexturesRemain()) {
// only try redrawing for layers if layer textures remain,
// otherwise we'll repaint without getting anything done
@@ -329,8 +379,6 @@ bool BaseLayerAndroid::drawGL(double currentTime, LayerAndroid* compositedRoot,
}
}
- m_previousVisible = visibleRect;
-
#endif // USE(ACCELERATED_COMPOSITING)
#ifdef DEBUG
ClassTracker::instance()->show();
diff --git a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.h b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.h
index 20942ec..c5ce52f 100644
--- a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.h
+++ b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.h
@@ -48,7 +48,6 @@ public:
virtual ~BaseLayerAndroid();
#if USE(ACCELERATED_COMPOSITING)
- void setGLWebViewState(GLWebViewState* infos) { m_glWebViewState = infos; }
void setBackgroundColor(Color& color) { m_color = color; }
Color getBackgroundColor() { return m_color; }
#endif
@@ -60,21 +59,29 @@ public:
// we are running in different threads.
virtual bool drawCanvas(SkCanvas* canvas);
- bool drawGL(double currentTime, LayerAndroid* compositedRoot, IntRect& rect,
- SkRect& viewport, float scale, bool* buffersSwappedPtr);
+ void updateLayerPositions(SkRect& visibleRect);
+ bool prepare(double currentTime, IntRect& viewRect,
+ SkRect& visibleRect, float scale);
+ bool drawGL(IntRect& viewRect, SkRect& visibleRect, float scale);
+
+ // rendering asset management
+ void swapTiles();
+ void setIsDrawing(bool isDrawing);
+ void setIsPainting(Layer* drawingTree);
+ void mergeInvalsInto(Layer* replacementTree);
+ bool isReady();
+
private:
#if USE(ACCELERATED_COMPOSITING)
void prefetchBasePicture(SkRect& viewport, float currentScale,
TiledPage* prefetchTiledPage, bool draw);
- bool drawBasePictureInGL(SkRect& viewport, float scale, double currentTime,
- bool* buffersSwappedPtr);
+ bool prepareBasePictureInGL(SkRect& viewport, float scale, double currentTime);
+ void drawBasePictureInGL();
- GLWebViewState* m_glWebViewState;
android::Mutex m_drawLock;
Color m_color;
#endif
android::PictureSet m_content;
- SkRect m_previousVisible;
ScrollState m_scrollState;
};
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 fa22593..273c478 100644
--- a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp
+++ b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp
@@ -37,6 +37,7 @@
#include "SkPath.h"
#include "TilesManager.h"
#include "TilesTracker.h"
+#include "TreeManager.h"
#include <wtf/CurrentTime.h>
#include <pthread.h>
@@ -74,20 +75,16 @@ using namespace android;
GLWebViewState::GLWebViewState()
: m_zoomManager(this)
- , m_paintingBaseLayer(0)
- , m_currentBaseLayer(0)
- , m_currentBaseLayerRoot(0)
, m_currentPictureCounter(0)
, m_usePageA(true)
, m_frameworkInval(0, 0, 0, 0)
, m_frameworkLayersInval(0, 0, 0, 0)
- , m_baseLayerUpdate(true)
- , m_backgroundColor(SK_ColorWHITE)
, m_isScrolling(false)
, m_goingDown(true)
, m_goingLeft(false)
, m_expandedTileBoundsX(0)
, m_expandedTileBoundsY(0)
+ , m_highEndGfx(false)
, m_scale(1)
, m_layersRenderingMode(kAllTextures)
{
@@ -111,10 +108,6 @@ GLWebViewState::GLWebViewState()
GLWebViewState::~GLWebViewState()
{
- // Unref the existing tree/PaintedSurfaces
- if (m_currentBaseLayerRoot)
- TilesManager::instance()->swapLayersTextures(m_currentBaseLayerRoot, 0);
-
// Take care of the transfer queue such that Tex Gen thread will not stuck
TilesManager::instance()->unregisterGLWebViewState(this);
@@ -126,12 +119,6 @@ GLWebViewState::~GLWebViewState()
// will remove any pending operations, and wait if one is underway).
delete m_tiledPageA;
delete m_tiledPageB;
- SkSafeUnref(m_paintingBaseLayer);
- SkSafeUnref(m_currentBaseLayer);
- SkSafeUnref(m_currentBaseLayerRoot);
- m_paintingBaseLayer = 0;
- m_currentBaseLayer = 0;
- m_currentBaseLayerRoot = 0;
#ifdef DEBUG_COUNT
ClassTracker::instance()->decrement("GLWebViewState");
#endif
@@ -141,49 +128,19 @@ GLWebViewState::~GLWebViewState()
void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval,
bool showVisualIndicator, bool isPictureAfterFirstLayout)
{
- android::Mutex::Autolock lock(m_baseLayerLock);
if (!layer || isPictureAfterFirstLayout) {
+ // TODO: move this into TreeManager
m_tiledPageA->discardTextures();
m_tiledPageB->discardTextures();
}
- if (isPictureAfterFirstLayout) {
- m_baseLayerUpdate = true;
- m_invalidateRegion.setEmpty();
- }
-
- SkSafeRef(layer);
- SkSafeUnref(m_currentBaseLayer);
- m_currentBaseLayer = layer;
-
- // copy content from old composited root to new
- LayerAndroid* oldRoot = m_currentBaseLayerRoot;
if (layer) {
- layer->setGLWebViewState(this);
- m_currentBaseLayerRoot = static_cast<LayerAndroid*>(layer->getChild(0));
- SkSafeRef(m_currentBaseLayerRoot);
- } else {
- m_currentBaseLayerRoot = 0;
- }
- if (oldRoot != m_currentBaseLayerRoot)
- TilesManager::instance()->swapLayersTextures(oldRoot, m_currentBaseLayerRoot);
- SkSafeUnref(oldRoot);
-
- // We only update the base layer if we are not currently
- // waiting for a tiledPage to be painted
- if (m_baseLayerUpdate) {
- SkSafeRef(layer);
- SkSafeUnref(m_paintingBaseLayer);
- m_paintingBaseLayer = layer;
+ XLOG("new base layer %p, (inval region empty %d) with child %p", layer, inval.isEmpty(), layer->getChild(0));
+ layer->setState(this);
+ layer->markAsDirty(inval); // TODO: set in webview.cpp
}
+ m_treeManager.updateWithTree(layer, isPictureAfterFirstLayout);
m_glExtras.setDrawExtra(0);
- // TODO: do the union of both layers tree to compute
- // the minimum inval instead of doing a fullInval()
- if (m_layersRenderingMode == kSingleSurfaceRendering)
- fullInval();
- else
- invalRegion(inval);
-
#ifdef MEASURES_PERF
if (m_measurePerfs && !showVisualIndicator)
dumpMeasures();
@@ -193,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)
@@ -203,6 +162,12 @@ void GLWebViewState::scrolledLayer(ScrollableLayerAndroid*)
void GLWebViewState::invalRegion(const SkRegion& region)
{
+ if (m_layersRenderingMode == kSingleSurfaceRendering) {
+ // TODO: do the union of both layers tree to compute
+ //the minimum inval instead of doing a fullInval()
+ fullInval();
+ return;
+ }
SkRegion::Iterator iterator(region);
while (!iterator.done()) {
SkIRect r = iterator.rect();
@@ -212,59 +177,27 @@ void GLWebViewState::invalRegion(const SkRegion& region)
}
}
-void GLWebViewState::unlockBaseLayerUpdate() {
- if (m_baseLayerUpdate)
- return;
-
- m_baseLayerUpdate = true;
- android::Mutex::Autolock lock(m_baseLayerLock);
- SkSafeRef(m_currentBaseLayer);
- SkSafeUnref(m_paintingBaseLayer);
- m_paintingBaseLayer = m_currentBaseLayer;
-
- invalRegion(m_invalidateRegion);
- m_invalidateRegion.setEmpty();
-}
-
void GLWebViewState::inval(const IntRect& rect)
{
- if (m_baseLayerUpdate) {
- // base layer isn't locked, so go ahead and issue the inval to both tiled pages
- m_currentPictureCounter++;
- if (!rect.isEmpty()) {
- // find which tiles fall within the invalRect and mark them as dirty
- m_tiledPageA->invalidateRect(rect, m_currentPictureCounter);
- m_tiledPageB->invalidateRect(rect, m_currentPictureCounter);
- if (m_frameworkInval.isEmpty())
- m_frameworkInval = rect;
- else
- m_frameworkInval.unite(rect);
- XLOG("intermediate invalRect(%d, %d, %d, %d) after unite with rect %d %d %d %d", m_frameworkInval.x(),
- m_frameworkInval.y(), m_frameworkInval.width(), m_frameworkInval.height(),
- rect.x(), rect.y(), rect.width(), rect.height());
- }
- } else {
- // base layer is locked, so defer invalidation until unlockBaseLayerUpdate()
- m_invalidateRegion.op(rect.x(), rect.y(), rect.maxX(), rect.maxY(), SkRegion::kUnion_Op);
+ m_currentPictureCounter++;
+ if (!rect.isEmpty()) {
+ // find which tiles fall within the invalRect and mark them as dirty
+ m_tiledPageA->invalidateRect(rect, m_currentPictureCounter);
+ m_tiledPageB->invalidateRect(rect, m_currentPictureCounter);
+ if (m_frameworkInval.isEmpty())
+ m_frameworkInval = rect;
+ else
+ m_frameworkInval.unite(rect);
+ XLOG("intermediate invalRect(%d, %d, %d, %d) after unite with rect %d %d %d %d", m_frameworkInval.x(),
+ m_frameworkInval.y(), m_frameworkInval.width(), m_frameworkInval.height(),
+ rect.x(), rect.y(), rect.width(), rect.height());
}
TilesManager::instance()->getProfiler()->nextInval(rect, zoomManager()->currentScale());
}
unsigned int GLWebViewState::paintBaseLayerContent(SkCanvas* canvas)
{
- m_baseLayerLock.lock();
- BaseLayerAndroid* base = m_paintingBaseLayer;
- SkSafeRef(base);
- m_baseLayerLock.unlock();
- if (base) {
- base->drawCanvas(canvas);
- if (m_layersRenderingMode == kSingleSurfaceRendering) {
- LayerAndroid* rootLayer = static_cast<LayerAndroid*>(base->getChild(0));
- if (rootLayer)
- rootLayer->drawCanvas(canvas);
- }
- }
- SkSafeUnref(base);
+ m_treeManager.drawCanvas(canvas, m_layersRenderingMode == kSingleSurfaceRendering);
return m_currentPictureCounter;
}
@@ -296,11 +229,11 @@ void GLWebViewState::swapPages()
int GLWebViewState::baseContentWidth()
{
- return m_paintingBaseLayer ? m_paintingBaseLayer->content()->width() : 0;
+ return m_treeManager.baseContentWidth();
}
int GLWebViewState::baseContentHeight()
{
- return m_paintingBaseLayer ? m_paintingBaseLayer->content()->height() : 0;
+ return m_treeManager.baseContentHeight();
}
void GLWebViewState::setViewport(SkRect& viewport, float scale)
@@ -332,7 +265,7 @@ void GLWebViewState::setViewport(SkRect& viewport, float scale)
int viewMaxTileY = static_cast<int>(ceilf((viewport.height()-1) * invTileContentHeight)) + 1;
int maxTextureCount = (viewMaxTileX + m_expandedTileBoundsX * 2) *
- (viewMaxTileY + m_expandedTileBoundsY * 2) * 2;
+ (viewMaxTileY + m_expandedTileBoundsY * 2) * (m_highEndGfx ? 4 : 2);
TilesManager::instance()->setMaxTextureCount(maxTextureCount);
m_tiledPageA->updateBaseTileSize();
@@ -381,41 +314,48 @@ void GLWebViewState::resetLayersDirtyArea()
m_frameworkLayersInval.setHeight(0);
}
-double GLWebViewState::setupDrawing(IntRect& viewRect, SkRect& visibleRect,
- IntRect& webViewRect, int titleBarHeight,
- IntRect& screenClip, float scale)
+void GLWebViewState::drawBackground(Color& backgroundColor)
{
- int left = viewRect.x();
- int top = viewRect.y();
- int width = viewRect.width();
- int height = viewRect.height();
-
if (TilesManager::instance()->invertedScreen()) {
- float color = 1.0 - ((((float) m_backgroundColor.red() / 255.0) +
- ((float) m_backgroundColor.green() / 255.0) +
- ((float) m_backgroundColor.blue() / 255.0)) / 3.0);
+ float color = 1.0 - ((((float) backgroundColor.red() / 255.0) +
+ ((float) backgroundColor.green() / 255.0) +
+ ((float) backgroundColor.blue() / 255.0)) / 3.0);
glClearColor(color, color, color, 1);
} else {
- glClearColor((float)m_backgroundColor.red() / 255.0,
- (float)m_backgroundColor.green() / 255.0,
- (float)m_backgroundColor.blue() / 255.0, 1);
+ glClearColor((float)backgroundColor.red() / 255.0,
+ (float)backgroundColor.green() / 255.0,
+ (float)backgroundColor.blue() / 255.0, 1);
}
glClear(GL_COLOR_BUFFER_BIT);
+}
- glViewport(left, top, width, height);
+double GLWebViewState::setupDrawing(IntRect& viewRect, SkRect& visibleRect,
+ IntRect& webViewRect, int titleBarHeight,
+ IntRect& screenClip, float scale)
+{
+ int left = viewRect.x();
+ int top = viewRect.y();
+ int width = viewRect.width();
+ int height = viewRect.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);
@@ -427,7 +367,13 @@ double GLWebViewState::setupDrawing(IntRect& viewRect, SkRect& visibleRect,
bool GLWebViewState::setLayersRenderingMode(TexturesResult& nbTexturesNeeded)
{
bool invalBase = false;
- int maxTextures = TilesManager::instance()->maxTextureCount();
+
+ if (!nbTexturesNeeded.full)
+ TilesManager::instance()->setMaxLayerTextureCount(0);
+ else
+ TilesManager::instance()->setMaxLayerTextureCount((2*nbTexturesNeeded.full)+1);
+
+ int maxTextures = TilesManager::instance()->maxLayerTextureCount();
LayersRenderingMode layersRenderingMode = m_layersRenderingMode;
m_layersRenderingMode = kSingleSurfaceRendering;
@@ -440,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;
@@ -489,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,
@@ -503,13 +453,6 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
TilesManager::instance()->getTilesTracker()->clear();
#endif
- m_baseLayerLock.lock();
- BaseLayerAndroid* baseLayer = m_paintingBaseLayer;
- SkSafeRef(baseLayer);
- m_baseLayerLock.unlock();
- if (!baseLayer)
- return false;
-
float viewWidth = (viewport.fRight - viewport.fLeft) * TILE_PREFETCH_RATIO;
float viewHeight = (viewport.fBottom - viewport.fTop) * TILE_PREFETCH_RATIO;
bool useMinimalMemory = TilesManager::instance()->useMinimalMemory();
@@ -524,17 +467,8 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
resetLayersDirtyArea();
- LayerAndroid* compositedRoot = m_currentBaseLayerRoot;
- LayerAndroid* paintingBaseLayerRoot = 0;
- if (baseLayer && baseLayer->countChildren() >= 1)
- paintingBaseLayerRoot = static_cast<LayerAndroid*>(baseLayer->getChild(0));
-
// when adding or removing layers, use the the paintingBaseLayer's tree so
// that content that moves to the base layer from a layer is synchronized
- bool paintingHasLayers = (paintingBaseLayerRoot == 0);
- bool currentHasLayers = (m_currentBaseLayerRoot == 0);
- if (paintingHasLayers != currentHasLayers)
- compositedRoot = paintingBaseLayerRoot;
if (scale < MIN_SCALE_WARNING || scale > MAX_SCALE_WARNING)
XLOGC("WARNING, scale seems corrupted before update: %e", scale);
@@ -547,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);
@@ -555,45 +489,27 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
// gather the textures we can use
TilesManager::instance()->gatherLayerTextures();
- // set up zoom manager, shaders, etc.
- m_backgroundColor = baseLayer->getBackgroundColor();
double currentTime = setupDrawing(rect, viewport, webViewRect, titleBarHeight, clip, scale);
- if (compositedRoot)
- compositedRoot->setState(this);
- bool animsRunning = false;
TexturesResult nbTexturesNeeded;
- if (compositedRoot) {
- TransformationMatrix ident;
- animsRunning = compositedRoot->evaluateAnimations();
- bool hasFixedElements = compositedRoot->updateFixedLayersPositions(viewport);
- if (m_layersRenderingMode == kSingleSurfaceRendering) {
- // If we are in single surface rendering, we may have to fully
- // invalidate if we have fixed elements or if we have CSS
- // animations.
- // TODO: compute the minimum invals
- if (animsRunning || hasFixedElements)
- fullInval();
- }
-
- // TODO: get the base document area for the original clip
- FloatRect clip(0, 0, 1E6, 1E6);
- compositedRoot->updateGLPositionsAndScale(ident, clip, 1, zoomManager()->layersScale());
- compositedRoot->prepare(this);
-
- ret |= animsRunning;
+ bool fastSwap = isScrolling() || m_layersRenderingMode == kSingleSurfaceRendering;
+ ret |= m_treeManager.drawGL(currentTime, rect, viewport,
+ scale, fastSwap,
+ treesSwappedPtr, newTreeHasAnimPtr,
+ &nbTexturesNeeded);
+ if (!ret)
+ resetFrameworkInval();
- compositedRoot->computeTexturesAmount(&nbTexturesNeeded);
- }
+ 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);
- // Clean up GL textures for video layer.
- TilesManager::instance()->videoLayerManager()->deleteUnusedTextures();
-
- ret |= baseLayer->drawGL(currentTime, compositedRoot, rect,
- viewport, scale, buffersSwappedPtr);
-
FloatRect extrasclip(0, 0, rect.width(), rect.height());
TilesManager::instance()->shader()->clip(extrasclip);
@@ -601,6 +517,8 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
glBindBuffer(GL_ARRAY_BUFFER, 0);
+ // Clean up GL textures for video layer.
+ TilesManager::instance()->videoLayerManager()->deleteUnusedTextures();
ret |= TilesManager::instance()->invertedScreenSwitch();
if (ret) {
@@ -656,7 +574,6 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
}
#endif
- SkSafeUnref(baseLayer);
#ifdef DEBUG
TilesManager::instance()->getTilesTracker()->showTrackTextures();
ImagesManager::instance()->showImages();
diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.h b/Source/WebCore/platform/graphics/android/GLWebViewState.h
index a1adaf1..8d89704 100644
--- a/Source/WebCore/platform/graphics/android/GLWebViewState.h
+++ b/Source/WebCore/platform/graphics/android/GLWebViewState.h
@@ -36,6 +36,7 @@
#include "SkRect.h"
#include "SkRegion.h"
#include "TiledPage.h"
+#include "TreeManager.h"
#include "ZoomManager.h"
#include <utils/threads.h>
@@ -200,22 +201,21 @@ public:
unsigned int currentPictureCounter() const { return m_currentPictureCounter; }
- void lockBaseLayerUpdate() { m_baseLayerUpdate = false; }
- void unlockBaseLayerUpdate();
-
void setIsScrolling(bool isScrolling) { m_isScrolling = isScrolling; }
bool isScrolling() { return m_isScrolling; }
- double setupDrawing(IntRect& rect, SkRect& viewport, IntRect& webViewRect,
- int titleBarHeight, IntRect& screenClip,
- float scale);
+ void drawBackground(Color& backgroundColor);
+ double setupDrawing(IntRect& viewRect, SkRect& visibleRect,
+ IntRect& webViewRect, int titleBarHeight,
+ IntRect& screenClip, float scale);
bool setLayersRenderingMode(TexturesResult&);
void fullInval();
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();
@@ -234,6 +234,7 @@ public:
int expandedTileBoundsX() { return m_expandedTileBoundsX; }
int expandedTileBoundsY() { return m_expandedTileBoundsY; }
+ void setHighEndGfx(bool highEnd) { m_highEndGfx = highEnd; }
float scale() { return m_scale; }
@@ -247,22 +248,19 @@ public:
};
LayersRenderingMode layersRenderingMode() { return m_layersRenderingMode; }
- void scrolledLayer(ScrollableLayerAndroid*);
+ void scrollLayer(int layerId, int x, int y);
-private:
- void inval(const IntRect& rect); // caller must hold m_baseLayerLock
void invalRegion(const SkRegion& region);
+private:
+ void inval(const IntRect& rect);
+
ZoomManager m_zoomManager;
android::Mutex m_tiledPageLock;
SkRect m_viewport;
SkIRect m_viewportTileBounds;
SkIRect m_futureViewportTileBounds;
SkIRect m_preZoomBounds;
- android::Mutex m_baseLayerLock;
- BaseLayerAndroid* m_paintingBaseLayer;
- BaseLayerAndroid* m_currentBaseLayer;
- LayerAndroid* m_currentBaseLayerRoot;
unsigned int m_currentPictureCounter;
bool m_usePageA;
@@ -272,11 +270,6 @@ private:
IntRect m_frameworkInval;
IntRect m_frameworkLayersInval;
- bool m_baseLayerUpdate;
- SkRegion m_invalidateRegion;
-
- Color m_backgroundColor;
-
#ifdef MEASURES_PERF
unsigned int m_totalTimeCounter;
int m_timeCounter;
@@ -291,10 +284,12 @@ private:
int m_expandedTileBoundsX;
int m_expandedTileBoundsY;
+ bool m_highEndGfx;
float m_scale;
LayersRenderingMode m_layersRenderingMode;
+ TreeManager m_treeManager;
};
} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp b/Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
index f647673..a490d5f 100644
--- a/Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
+++ b/Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
@@ -1207,10 +1207,11 @@ AffineTransform GraphicsContext::getCTM() const
void GraphicsContext::setCTM(const AffineTransform& transform)
{
- if (paintingDisabled())
- return;
-
- GC2CANVAS(this)->setMatrix(transform);
+ // The SkPicture mode of Skia does not support SkCanvas::setMatrix(), so we
+ // can not simply use that method here. We could calculate the transform
+ // required to achieve the desired matrix and use SkCanvas::concat(), but
+ // there's currently no need for this.
+ ASSERT_NOT_REACHED();
}
///////////////////////////////////////////////////////////////////////////////
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 7f35f06..6c6a075 100644
--- a/Source/WebCore/platform/graphics/android/ImageTexture.h
+++ b/Source/WebCore/platform/graphics/android/ImageTexture.h
@@ -26,61 +26,81 @@
#ifndef ImageTexture_h
#define ImageTexture_h
-#include "ClassTracker.h"
#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/Layer.cpp b/Source/WebCore/platform/graphics/android/Layer.cpp
index f650c52..9280461 100644
--- a/Source/WebCore/platform/graphics/android/Layer.cpp
+++ b/Source/WebCore/platform/graphics/android/Layer.cpp
@@ -23,6 +23,7 @@ Layer::Layer() {
m_shouldInheritFromRootTransform = false;
m_hasOverflowChildren = false;
+ m_state = 0;
#ifdef DEBUG_TRACK_NEW_DELETE
gLayerAllocCount += 1;
@@ -42,6 +43,7 @@ Layer::Layer(const Layer& src) : INHERITED() {
m_shouldInheritFromRootTransform = src.m_shouldInheritFromRootTransform;
m_hasOverflowChildren = src.m_hasOverflowChildren;
+ m_state = 0;
#ifdef DEBUG_TRACK_NEW_DELETE
gLayerAllocCount += 1;
@@ -225,3 +227,10 @@ bool Layer::isAncestor(const Layer* possibleAncestor) const {
}
return false;
}
+
+void Layer::setState(WebCore::GLWebViewState* state) {
+ m_state = state;
+ int count = countChildren();
+ for (int i = 0; i < count; i++)
+ m_children[i]->setState(state);
+}
diff --git a/Source/WebCore/platform/graphics/android/Layer.h b/Source/WebCore/platform/graphics/android/Layer.h
index 89e101c..5200a3d 100644
--- a/Source/WebCore/platform/graphics/android/Layer.h
+++ b/Source/WebCore/platform/graphics/android/Layer.h
@@ -17,17 +17,24 @@
#ifndef Layer_DEFINED
#define Layer_DEFINED
+#include "TestExport.h"
#include "SkRefCnt.h"
#include "SkTDArray.h"
#include "SkColor.h"
#include "SkMatrix.h"
#include "SkPoint.h"
#include "SkRect.h"
+#include "SkRegion.h"
#include "SkSize.h"
+namespace WebCore {
+class IntRect;
+class GLWebViewState;
+};
+
class SkCanvas;
-class Layer : public SkRefCnt {
+class TEST_EXPORT Layer : public SkRefCnt {
public:
Layer();
@@ -56,7 +63,42 @@ public:
void setMatrix(const SkMatrix& matrix) { m_matrix = matrix; }
void setChildrenMatrix(const SkMatrix& matrix) { m_childrenMatrix = matrix; }
- // children
+// rendering asset management
+
+ // tell rendering assets to update their tile content with most recent painted data
+ virtual void swapTiles() {}
+
+ // tell rendering assets to use this layer tree for drawing
+ virtual void setIsDrawing(bool isDrawing) {}
+
+ // take rendering assets from drawing tree, or create if they don't exist
+ virtual void setIsPainting(Layer* drawingTree) {}
+
+ // if a similar layer exists in the replacement tree, add invals to it
+ virtual void mergeInvalsInto(Layer* replacementTree) {}
+
+ void markAsDirty(const SkRegion& invalRegion) {
+ m_dirtyRegion.op(invalRegion, SkRegion::kUnion_Op);
+ }
+
+ bool isDirty() {
+ return !m_dirtyRegion.isEmpty();
+ }
+
+// drawing
+
+ virtual bool isReady() { return false; }
+
+ // TODO: clean out several of these, leave them in GLWebViewState
+
+ virtual bool prepare(double currentTime, WebCore::IntRect& viewRect,
+ SkRect& visibleRect, float scale) { return 0; }
+ virtual bool drawGL(WebCore::IntRect& viewRect,
+ SkRect& visibleRect, float scale) { return 0; }
+ WebCore::GLWebViewState* state() { return m_state; }
+ void setState(WebCore::GLWebViewState* state);
+
+// children
/** Return the number of layers in our child list.
*/
@@ -153,6 +195,11 @@ protected:
SkTDArray<Layer*> m_children;
+ // invalidation region
+ SkRegion m_dirtyRegion;
+
+ WebCore::GLWebViewState* m_state;
+
typedef SkRefCnt INHERITED;
};
diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp
index 12a11bf..962bcdf 100644
--- a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp
+++ b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp
@@ -149,21 +149,17 @@ 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_requestSent(false),
m_scale(1),
m_lastComputeTextureSize(0),
m_owningLayer(owner),
m_type(LayerAndroid::WebCoreLayer),
- m_state(0),
m_hasText(true)
{
m_backgroundColor = 0;
m_preserves3D = false;
- m_dirty = false;
m_iframeOffset.set(0,0);
m_dirtyRegion.setEmpty();
#ifdef DEBUG_COUNT
@@ -177,17 +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_requestSent(false),
m_owningLayer(layer.m_owningLayer),
m_type(LayerAndroid::UILayer),
- m_state(0),
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;
@@ -211,7 +205,6 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : Layer(layer),
m_anchorPointZ = layer.m_anchorPointZ;
m_drawTransform = layer.m_drawTransform;
m_childrenTransform = layer.m_childrenTransform;
- m_dirty = layer.m_dirty;
m_pictureUsed = layer.m_pictureUsed;
m_dirtyRegion = layer.m_dirtyRegion;
m_scale = layer.m_scale;
@@ -222,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
}
@@ -256,20 +248,16 @@ LayerAndroid::LayerAndroid(SkPicture* picture) : Layer(),
m_isFixed(false),
m_isIframe(false),
m_recordingPicture(picture),
- m_uniqueId(-1),
+ m_uniqueId(++gUniqueId),
m_texture(0),
- m_imageRef(0),
- m_imageTexture(0),
- m_requestSent(false),
+ m_imageCRC(0),
m_scale(1),
m_lastComputeTextureSize(0),
m_owningLayer(0),
m_type(LayerAndroid::NavCacheLayer),
- m_state(0),
m_hasText(true)
{
m_backgroundColor = 0;
- m_dirty = false;
SkSafeRef(m_recordingPicture);
m_iframeOffset.set(0,0);
m_dirtyRegion.setEmpty();
@@ -281,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
@@ -335,7 +324,18 @@ bool LayerAndroid::evaluateAnimations(double time)
return hasRunningAnimations || m_hasRunningAnimations;
}
-void LayerAndroid::addDirtyArea(GLWebViewState* glWebViewState)
+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());
@@ -345,7 +345,7 @@ void LayerAndroid::addDirtyArea(GLWebViewState* glWebViewState)
area.intersect(clip);
IntRect dirtyArea(area.x(), area.y(), area.width(), area.height());
- glWebViewState->addDirtyArea(dirtyArea);
+ m_state->addDirtyArea(dirtyArea);
}
void LayerAndroid::addAnimation(PassRefPtr<AndroidAnimation> prpAnim)
@@ -379,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...
@@ -770,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 || (prepareContext()
+ return m_imageCRC || (m_recordingPicture
&& m_recordingPicture->width() && m_recordingPicture->height());
}
@@ -820,6 +818,9 @@ int LayerAndroid::nbTexturedLayers()
void LayerAndroid::computeTexturesAmount(TexturesResult* result)
{
+ if (!result)
+ return;
+
int count = this->countChildren();
for (int i = 0; i < count; i++)
this->getChild(i)->computeTexturesAmount(result);
@@ -847,15 +848,17 @@ 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) "
- "clip (%d, %d, %d, %d) %s prepareContext(%d), pic w: %d h: %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(),
contentIsScrollable() ? "SCROLLABLE" : "",
- prepareContext(),
+ isFixed() ? "FIXED" : "",
+ m_recordingPicture,
m_recordingPicture ? m_recordingPicture->width() : -1,
m_recordingPicture ? m_recordingPicture->height() : -1);
@@ -864,33 +867,68 @@ void LayerAndroid::showLayer(int indent)
this->getChild(i)->showLayer(indent + 1);
}
-// We go through our tree, and if we have layer in the new
-// tree that is similar, we transfer our texture to it.
-// Otherwise, we remove ourselves from the texture so
-// that TilesManager::swapLayersTextures() have a chance
-// at deallocating the textures (PaintedSurfaces)
-void LayerAndroid::assignTextureTo(LayerAndroid* newTree)
+void LayerAndroid::swapTiles()
{
int count = this->countChildren();
for (int i = 0; i < count; i++)
- this->getChild(i)->assignTextureTo(newTree);
+ this->getChild(i)->swapTiles();
- if (newTree) {
- LayerAndroid* newLayer = newTree->findById(uniqueId());
- if (newLayer == this)
- return;
- if (newLayer && m_texture) {
- m_texture->replaceLayer(newLayer);
- newLayer->m_texture = m_texture;
- m_texture = 0;
- }
- if (!newLayer && m_texture) {
- m_texture->removeLayer(this);
- m_texture = 0;
- }
+ if (m_texture)
+ m_texture->swapTiles();
+}
+
+void LayerAndroid::setIsDrawing(bool isDrawing)
+{
+ int count = this->countChildren();
+ for (int i = 0; i < count; i++)
+ this->getChild(i)->setIsDrawing(isDrawing);
+
+ if (m_texture) {
+ m_texture->setDrawingLayer(isDrawing ? this : 0);
+ m_texture->clearPaintingLayer();
}
}
+void LayerAndroid::setIsPainting(Layer* drawingTree)
+{
+ XLOG("setting layer %p as painting, needs texture %d, drawing tree %p",
+ this, needsTexture(), drawingTree);
+ int count = this->countChildren();
+ for (int i = 0; i < count; i++)
+ this->getChild(i)->setIsPainting(drawingTree);
+
+
+ LayerAndroid* drawingLayer = 0;
+ if (drawingTree)
+ drawingLayer = static_cast<LayerAndroid*>(drawingTree)->findById(uniqueId());
+
+ obtainTextureForPainting(drawingLayer);
+}
+
+void LayerAndroid::mergeInvalsInto(Layer* replacementTree)
+{
+ int count = this->countChildren();
+ for (int i = 0; i < count; i++)
+ this->getChild(i)->mergeInvalsInto(replacementTree);
+
+ LayerAndroid* replacementLayer = static_cast<LayerAndroid*>(replacementTree)->findById(uniqueId());
+ if (replacementLayer)
+ replacementLayer->markAsDirty(m_dirtyRegion);
+}
+
+bool LayerAndroid::isReady()
+{
+ int count = countChildren();
+ for (int i = 0; i < count; i++)
+ if (!getChild(i)->isReady())
+ return false;
+
+ if (m_texture)
+ return m_texture->isReady();
+ // TODO: image, check if uploaded?
+ return true;
+}
+
bool LayerAndroid::updateWithTree(LayerAndroid* newTree)
{
// Disable fast update for now
@@ -925,54 +963,48 @@ 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::createTexture()
+void LayerAndroid::obtainTextureForPainting(LayerAndroid* drawingLayer)
{
- int count = this->countChildren();
- for (int i = 0; i < count; i++)
- this->getChild(i)->createTexture();
-
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->removeLayer(this);
+ m_texture->setDrawingLayer(0);
+ m_texture->clearPaintingLayer();
m_texture = 0;
}
} else {
+ if (drawingLayer) {
+ // if a previous tree had the same layer, paint with that painted surface
+ m_texture = drawingLayer->m_texture;
+ }
+
if (!m_texture)
- m_texture = new PaintedSurface(this);
+ m_texture = new PaintedSurface();
// pass the invalidated regions to the PaintedSurface
- m_texture->markAsDirty(m_dirtyRegion);
- m_dirtyRegion.setEmpty();
+ m_texture->setPaintingLayer(this, m_dirtyRegion);
}
+ m_dirtyRegion.setEmpty();
}
+
static inline bool compareLayerZ(const LayerAndroid* a, const LayerAndroid* b)
{
return a->zValue() > b->zValue();
}
-void LayerAndroid::markAsDirty(const SkRegion& dirtyArea)
-{
- m_dirtyRegion.op(dirtyArea, SkRegion::kUnion_Op);
-}
-
// We call this in WebViewCore, when copying the tree of layers.
// As we construct a new tree that will be passed on the UI,
// we mark the webkit-side tree as having no more dirty region
@@ -986,18 +1018,9 @@ void LayerAndroid::clearDirtyRegion()
m_dirtyRegion.setEmpty();
}
-void LayerAndroid::setState(GLWebViewState* state)
-{
- int count = this->countChildren();
- for (int i = 0; i < count; i++)
- this->getChild(i)->setState(state);
-
- m_state = state;
-}
-
-void LayerAndroid::prepare(GLWebViewState* glWebViewState)
+void LayerAndroid::prepare()
{
- m_state = glWebViewState;
+ XLOG("LA %p preparing, m_texture %p", this, m_texture);
int count = this->countChildren();
if (count > 0) {
@@ -1010,14 +1033,11 @@ void LayerAndroid::prepare(GLWebViewState* glWebViewState)
// iterate in reverse so top layers get textures first
for (int i = count-1; i >= 0; i--)
- sublayers[i]->prepare(glWebViewState);
+ sublayers[i]->prepare();
}
if (m_texture)
- m_texture->prepare(glWebViewState);
-
- if (m_imageTexture)
- m_imageTexture->prepareGL();
+ m_texture->prepare(m_state);
}
IntRect LayerAndroid::unclippedArea()
@@ -1082,15 +1102,14 @@ bool LayerAndroid::drawCanvas(SkCanvas* canvas)
// When the layer is dirty, the UI thread should be notified to redraw.
askScreenUpdate |= drawChildrenCanvas(canvas);
m_atomicSync.lock();
- askScreenUpdate |= m_dirty;
if (askScreenUpdate || m_hasRunningAnimations || m_drawTransform.hasPerspective())
- addDirtyArea(m_state);
+ addDirtyArea();
m_atomicSync.unlock();
return askScreenUpdate;
}
-bool LayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix)
+bool LayerAndroid::drawGL()
{
FloatRect clippingRect = TilesManager::instance()->shader()->rectInScreenCoord(m_clippingRect);
TilesManager::instance()->shader()->clip(clippingRect);
@@ -1099,18 +1118,22 @@ bool LayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix)
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(glWebViewState, matrix);
+ askScreenUpdate |= drawChildrenGL();
m_atomicSync.lock();
- askScreenUpdate |= m_dirty;
if (askScreenUpdate || m_hasRunningAnimations || m_drawTransform.hasPerspective())
- addDirtyArea(glWebViewState);
+ addDirtyArea();
m_atomicSync.unlock();
return askScreenUpdate;
@@ -1136,7 +1159,7 @@ bool LayerAndroid::drawChildrenCanvas(SkCanvas* canvas)
return askScreenUpdate;
}
-bool LayerAndroid::drawChildrenGL(GLWebViewState* glWebViewState, SkMatrix& matrix)
+bool LayerAndroid::drawChildrenGL()
{
bool askScreenUpdate = false;
int count = this->countChildren();
@@ -1149,7 +1172,7 @@ bool LayerAndroid::drawChildrenGL(GLWebViewState* glWebViewState, SkMatrix& matr
std::stable_sort(sublayers.begin(), sublayers.end(), compareLayerZ);
for (int i = 0; i < count; i++) {
LayerAndroid* layer = sublayers[i];
- askScreenUpdate |= layer->drawGL(glWebViewState, matrix);
+ askScreenUpdate |= layer->drawGL();
}
}
@@ -1201,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 b536b22..c1f1bc9 100644
--- a/Source/WebCore/platform/graphics/android/LayerAndroid.h
+++ b/Source/WebCore/platform/graphics/android/LayerAndroid.h
@@ -30,11 +30,9 @@
#include "SkColor.h"
#include "SkRegion.h"
#include "SkStream.h"
-#include "TextureOwner.h"
#include "TransformationMatrix.h"
#include <wtf/HashMap.h>
-#include <wtf/text/StringHash.h>
#ifndef BZERO_DEFINED
#define BZERO_DEFINED
@@ -94,6 +92,7 @@ namespace WebCore {
class AndroidAnimation;
class BaseTileTexture;
+class GLWebViewState;
class LayerAndroidFindState;
class RenderLayer;
class TiledPage;
@@ -114,7 +113,7 @@ public:
int full;
};
-class LayerAndroid : public Layer {
+class TEST_EXPORT LayerAndroid : public Layer {
public:
enum LayerType { UndefinedLayer, WebCoreLayer, UILayer, NavCacheLayer };
@@ -124,7 +123,6 @@ public:
virtual ~LayerAndroid();
virtual TiledPage* page() { return 0; }
- virtual GLWebViewState* state() { return m_state; }
void setBackfaceVisibility(bool value) { m_backfaceVisibility = value; }
void setTransform(const TransformationMatrix& matrix) { m_transform = matrix; }
@@ -146,22 +144,20 @@ public:
// Debug helper methods
int nbLayers();
int nbTexturedLayers();
- void showLayer(int indent);
+ void showLayer(int indent = 0);
void computeTexturesAmount(TexturesResult*);
float getScale() { return m_scale; }
- void setState(GLWebViewState*);
-
// draw layer and its children via Z, pre-order traversal
- virtual bool drawGL(GLWebViewState*, SkMatrix&);
- bool drawChildrenGL(GLWebViewState*, SkMatrix&);
+ virtual bool drawGL();
+ bool drawChildrenGL();
virtual bool drawCanvas(SkCanvas*);
bool drawChildrenCanvas(SkCanvas*);
// prepare layer and its children via reverse-Z, post-order traversal
- void prepare(GLWebViewState*);
+ void prepare();
void updateGLPositionsAndScale(const TransformationMatrix& parentMatrix,
const FloatRect& clip, float opacity, float scale);
@@ -218,8 +214,9 @@ public:
void removeAnimationsForKeyframes(const String& name);
bool evaluateAnimations();
bool evaluateAnimations(double time);
+ void initAnimations();
bool hasAnimations() const;
- void addDirtyArea(GLWebViewState*);
+ void addDirtyArea();
SkPicture* picture() const { return m_recordingPicture; }
@@ -264,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);
@@ -276,9 +273,7 @@ public:
void needsRepaint() { m_pictureUsed++; }
unsigned int pictureUsed() { return m_pictureUsed; }
- void markAsDirty(const SkRegion& dirtyArea);
void clearDirtyRegion();
- const SkRegion& dirtyRegion() { return m_dirtyRegion; }
void contentDraw(SkCanvas*);
@@ -296,8 +291,7 @@ public:
friend void android::cleanupImageRefs(LayerAndroid* layer);
PaintedSurface* texture() { return m_texture; }
- void assignTextureTo(LayerAndroid* newTree);
- void createTexture();
+ 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
@@ -305,13 +299,20 @@ 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);
+ void setIsPainting(Layer* drawingTree);
+ void mergeInvalsInto(Layer* replacementTree);
+ bool isReady();
+
protected:
virtual void onDraw(SkCanvas*, SkScalar opacity);
@@ -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,22 +388,13 @@ private:
int m_uniqueId;
PaintedSurface* m_texture;
- SkBitmapRef* m_imageRef;
- ImageTexture* m_imageTexture;
+ unsigned m_imageCRC;
- // used to signal that the tile is out-of-date and needs to be redrawn
- bool m_dirty;
unsigned int m_pictureUsed;
- // dirty regions
- SkRegion m_dirtyRegion;
-
// used to signal the framework we need a repaint
bool m_hasRunningAnimations;
- // painting request sent
- bool m_requestSent;
-
float m_scale;
// We try to not always compute the texture size, as this is quite heavy
@@ -416,7 +409,6 @@ private:
RenderLayer* m_owningLayer;
int m_type;
- GLWebViewState* m_state;
bool m_hasText;
diff --git a/Source/WebCore/platform/graphics/android/MediaLayer.cpp b/Source/WebCore/platform/graphics/android/MediaLayer.cpp
index 7fa5ac2..12cfe38 100644
--- a/Source/WebCore/platform/graphics/android/MediaLayer.cpp
+++ b/Source/WebCore/platform/graphics/android/MediaLayer.cpp
@@ -66,9 +66,10 @@ MediaLayer::~MediaLayer()
m_mediaTexture->decStrong(this);
}
-bool MediaLayer::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix)
+bool MediaLayer::drawGL()
{
- TilesManager::instance()->shader()->clip(drawClip());
+ FloatRect clippingRect = TilesManager::instance()->shader()->rectInScreenCoord(drawClip());
+ TilesManager::instance()->shader()->clip(clippingRect);
// when the plugin gains focus webkit applies an outline to the
// widget, which causes the layer to expand to accommodate the
@@ -92,7 +93,7 @@ bool MediaLayer::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix)
// draw any content or video if present
m_mediaTexture->draw(m, m_drawTransform, mediaBounds);
- return drawChildrenGL(glWebViewState, matrix);
+ return drawChildrenGL();
}
ANativeWindow* MediaLayer::acquireNativeWindowForContent()
diff --git a/Source/WebCore/platform/graphics/android/MediaLayer.h b/Source/WebCore/platform/graphics/android/MediaLayer.h
index ef84abf..b94ec53 100644
--- a/Source/WebCore/platform/graphics/android/MediaLayer.h
+++ b/Source/WebCore/platform/graphics/android/MediaLayer.h
@@ -36,7 +36,7 @@ public:
MediaLayer(const MediaLayer& layer);
virtual ~MediaLayer();
- virtual bool drawGL(GLWebViewState*, SkMatrix&);
+ virtual bool drawGL();
virtual void paintBitmapGL() const { };
virtual bool needsTexture() { return false; }
diff --git a/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp b/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp
index d9a729a..2d69706 100644
--- a/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp
+++ b/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp
@@ -25,23 +25,21 @@
#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)
- , m_layer(0)
{
if (m_tile)
m_tile->setRepaintPending(true);
- if (m_surface)
- m_layer = surface->layer();
SkSafeRef(m_surface);
- SkSafeRef(m_layer);
}
PaintTileOperation::~PaintTileOperation()
@@ -50,8 +48,13 @@ PaintTileOperation::~PaintTileOperation()
m_tile->setRepaintPending(false);
m_tile = 0;
}
- SkSafeUnref(m_surface);
- SkSafeUnref(m_layer);
+
+ 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)
@@ -99,7 +102,6 @@ int PaintTileOperation::priority()
// for base tiles, prioritize based on position
if (!m_tile->isLayerTile()) {
bool goingDown = m_tile->page()->scrollingDown();
- SkIRect *rect = m_tile->page()->expandedTileBounds();
priority += m_tile->x();
if (goingDown)
diff --git a/Source/WebCore/platform/graphics/android/PaintTileOperation.h b/Source/WebCore/platform/graphics/android/PaintTileOperation.h
index 65d20f2..bc74d03 100644
--- a/Source/WebCore/platform/graphics/android/PaintTileOperation.h
+++ b/Source/WebCore/platform/graphics/android/PaintTileOperation.h
@@ -26,16 +26,19 @@
#ifndef PaintTileSetOperation_h
#define PaintTileSetOperation_h
+#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();
@@ -46,8 +49,7 @@ public:
private:
BaseTile* m_tile;
- PaintedSurface* m_surface;
- LayerAndroid* m_layer;
+ 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 939d106..d3c1e15 100644
--- a/Source/WebCore/platform/graphics/android/PaintedSurface.cpp
+++ b/Source/WebCore/platform/graphics/android/PaintedSurface.cpp
@@ -28,6 +28,7 @@
#include "LayerAndroid.h"
+#include "TiledTexture.h"
#include "TilesManager.h"
#include "SkCanvas.h"
#include "SkPicture.h"
@@ -57,107 +58,64 @@
namespace WebCore {
-PaintedSurface::PaintedSurface(LayerAndroid* layer)
- : m_layer(layer)
+PaintedSurface::PaintedSurface()
+ : m_drawingLayer(0)
+ , m_paintingLayer(0)
, m_tiledTexture(0)
, m_scale(0)
, m_pictureUsed(0)
{
TilesManager::instance()->addPaintedSurface(this);
- SkSafeRef(m_layer);
#ifdef DEBUG_COUNT
ClassTracker::instance()->increment("PaintedSurface");
#endif
m_tiledTexture = new DualTiledTexture(this);
- if (layer && layer->picture())
- m_updateManager.updatePicture(layer->picture());
}
PaintedSurface::~PaintedSurface()
{
- XLOG("dtor of %x m_layer: %x", this, m_layer);
- android::Mutex::Autolock lock(m_layerLock);
- SkSafeUnref(m_layer);
#ifdef DEBUG_COUNT
ClassTracker::instance()->decrement("PaintedSurface");
#endif
delete m_tiledTexture;
}
-void PaintedSurface::removeLayer()
-{
- android::Mutex::Autolock lock(m_layerLock);
- if (m_layer)
- m_layer->removeTexture(this);
- SkSafeUnref(m_layer);
- m_layer = 0;
-}
-
-void PaintedSurface::removeLayer(LayerAndroid* layer)
-{
- android::Mutex::Autolock lock(m_layerLock);
- if (m_layer != layer)
- return;
- SkSafeUnref(m_layer);
- m_layer = 0;
-}
-
-void PaintedSurface::replaceLayer(LayerAndroid* layer)
-{
- android::Mutex::Autolock lock(m_layerLock);
- if (!layer)
- return;
-
- if (m_layer && layer->uniqueId() != m_layer->uniqueId())
- return;
-
- SkSafeRef(layer);
- SkSafeUnref(m_layer);
- m_layer = layer;
- if (layer && layer->picture())
- m_updateManager.updatePicture(layer->picture());
-}
-
void PaintedSurface::prepare(GLWebViewState* state)
{
- if (!m_layer)
- return;
+ XLOG("PS %p has PL %p, DL %p", this, m_paintingLayer, m_drawingLayer);
+ LayerAndroid* paintingLayer = m_paintingLayer;
+ if (!paintingLayer)
+ paintingLayer = m_drawingLayer;
- if (!m_layer->needsTexture())
+ if (!paintingLayer)
return;
bool startFastSwap = false;
if (state->isScrolling()) {
// when scrolling, block updates and swap tiles as soon as they're ready
startFastSwap = true;
- } else {
- // when not, push updates down to TiledTexture in every prepare
- m_updateManager.swap();
- m_tiledTexture->update(m_updateManager.getPaintingInval(),
- m_updateManager.getPaintingPicture());
- m_updateManager.clearPaintingInval();
}
XLOG("prepare layer %d %x at scale %.2f",
- m_layer->uniqueId(), m_layer,
- m_layer->getScale());
+ paintingLayer->uniqueId(), paintingLayer,
+ paintingLayer->getScale());
- IntRect visibleArea = computeVisibleArea(m_layer);
+ IntRect visibleArea = computeVisibleArea(paintingLayer);
m_scale = state->scale();
// If we do not have text, we may as well limit ourselves to
// a scale factor of one... this saves up textures.
- if (m_scale > 1 && !m_layer->hasText())
+ if (m_scale > 1 && !paintingLayer->hasText())
m_scale = 1;
- m_tiledTexture->prepare(state, m_scale, m_pictureUsed != m_layer->pictureUsed(),
+ m_tiledTexture->prepare(state, m_scale, m_pictureUsed != paintingLayer->pictureUsed(),
startFastSwap, visibleArea);
}
bool PaintedSurface::draw()
{
- if (!m_layer || !m_layer->needsTexture())
+ if (!m_drawingLayer || !m_drawingLayer->needsTexture())
return false;
bool askRedraw = false;
@@ -167,22 +125,38 @@ bool PaintedSurface::draw()
return askRedraw;
}
-void PaintedSurface::markAsDirty(const SkRegion& dirtyArea)
+void PaintedSurface::setPaintingLayer(LayerAndroid* layer, const SkRegion& dirtyArea)
+{
+ m_paintingLayer = layer;
+ if (m_tiledTexture)
+ m_tiledTexture->update(dirtyArea, layer->picture());
+}
+
+bool PaintedSurface::isReady()
+{
+ if (m_tiledTexture)
+ return m_tiledTexture->isReady();
+ return false;
+}
+
+void PaintedSurface::swapTiles()
{
- m_updateManager.updateInval(dirtyArea);
+ if (m_tiledTexture)
+ m_tiledTexture->swapTiles();
}
float PaintedSurface::opacity() {
- if (m_layer)
- return m_layer->drawOpacity();
+ if (m_drawingLayer)
+ return m_drawingLayer->drawOpacity();
return 1.0;
}
const TransformationMatrix* PaintedSurface::transform() {
- if (!m_layer)
+ // used exclusively for drawing, so only use m_drawingLayer
+ if (!m_drawingLayer)
return 0;
- return m_layer->drawTransform();
+ return m_drawingLayer->drawTransform();
}
void PaintedSurface::computeTexturesAmount(TexturesResult* result)
@@ -190,11 +164,14 @@ void PaintedSurface::computeTexturesAmount(TexturesResult* result)
if (!m_tiledTexture)
return;
- if (!m_layer)
+ // for now, always done on drawinglayer
+ LayerAndroid* layer = m_drawingLayer;
+
+ if (!layer)
return;
- IntRect unclippedArea = m_layer->unclippedArea();
- IntRect clippedVisibleArea = m_layer->visibleArea();
+ IntRect unclippedArea = layer->unclippedArea();
+ IntRect clippedVisibleArea = layer->visibleArea();
// get two numbers here:
// - textures needed for a clipped area
// - textures needed for an un-clipped area
@@ -202,19 +179,19 @@ void PaintedSurface::computeTexturesAmount(TexturesResult* result)
int nbTexturesClipped = m_tiledTexture->nbTextures(clippedVisibleArea, m_scale);
// Set kFixedLayers level
- if (m_layer->isFixed())
+ if (layer->isFixed())
result->fixed += nbTexturesClipped;
// Set kScrollableAndFixedLayers level
- if (m_layer->contentIsScrollable()
- || m_layer->isFixed())
+ if (layer->contentIsScrollable()
+ || layer->isFixed())
result->scrollable += nbTexturesClipped;
// Set kClippedTextures level
result->clipped += nbTexturesClipped;
// Set kAllTextures level
- if (m_layer->contentIsScrollable())
+ if (layer->contentIsScrollable())
result->full += nbTexturesClipped;
else
result->full += nbTexturesUnclipped;
diff --git a/Source/WebCore/platform/graphics/android/PaintedSurface.h b/Source/WebCore/platform/graphics/android/PaintedSurface.h
index 83b2c9b..b8ab7b8 100644
--- a/Source/WebCore/platform/graphics/android/PaintedSurface.h
+++ b/Source/WebCore/platform/graphics/android/PaintedSurface.h
@@ -32,34 +32,37 @@
#include "LayerAndroid.h"
#include "SkRefCnt.h"
#include "TextureOwner.h"
-#include "TiledTexture.h"
#include "TilesManager.h"
#include "TilePainter.h"
#include "TransformationMatrix.h"
-#include "UpdateManager.h"
class SkCanvas;
class SkRegion;
namespace WebCore {
-class UpdateManager;
+class DualTiledTexture;
-class PaintedSurface : public SkRefCnt {
+class PaintedSurface : public SurfacePainter {
public:
- PaintedSurface(LayerAndroid* layer);
+ PaintedSurface();
virtual ~PaintedSurface();
// PaintedSurface methods
- LayerAndroid* layer() { return m_layer; }
void prepare(GLWebViewState*);
bool draw();
- void markAsDirty(const SkRegion& dirtyArea);
bool paint(SkCanvas*);
- void removeLayer();
- void removeLayer(LayerAndroid* layer);
- void replaceLayer(LayerAndroid* layer);
+
+ void setDrawingLayer(LayerAndroid* layer) { m_drawingLayer = layer; }
+ LayerAndroid* drawingLayer() { return m_drawingLayer; }
+
+ void setPaintingLayer(LayerAndroid* layer, const SkRegion& dirtyArea);
+ void clearPaintingLayer() { m_paintingLayer = 0; }
+ LayerAndroid* paintingLayer() { return m_paintingLayer; }
+
+ void swapTiles();
+ bool isReady();
bool owns(BaseTileTexture* texture);
@@ -68,16 +71,15 @@ 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:
- UpdateManager m_updateManager;
-
- LayerAndroid* m_layer;
+ LayerAndroid* m_drawingLayer;
+ LayerAndroid* m_paintingLayer;
DualTiledTexture* m_tiledTexture;
float m_scale;
diff --git a/Source/WebCore/platform/graphics/android/QueuedOperation.h b/Source/WebCore/platform/graphics/android/QueuedOperation.h
index a2e49a7..1a83f65 100644
--- a/Source/WebCore/platform/graphics/android/QueuedOperation.h
+++ b/Source/WebCore/platform/graphics/android/QueuedOperation.h
@@ -26,10 +26,10 @@
#ifndef QueuedOperation_h
#define QueuedOperation_h
-#include "TiledPage.h"
-
namespace WebCore {
+class TiledPage;
+
class QueuedOperation {
public:
enum OperationType { Undefined, PaintTile, PaintLayer, DeleteTexture };
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 30b5c86..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);
@@ -409,7 +417,8 @@ void ShaderProgram::setViewRect(const IntRect& viewRect)
translate.scale3d(1, -1, 1);
m_documentToInvScreenMatrix = scale * translate * m_projectionMatrix;
- m_documentViewport = m_documentToScreenMatrix.inverse().mapRect(viewRect);
+ IntRect rect(0, 0, m_webViewRect.width(), m_webViewRect.height());
+ m_documentViewport = m_documentToScreenMatrix.inverse().mapRect(rect);
}
// This function transform a clip rect extracted from the current layer
@@ -559,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);
@@ -626,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/TestExport.h b/Source/WebCore/platform/graphics/android/TestExport.h
new file mode 100644
index 0000000..15d7cc3
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/TestExport.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TestExport_h
+#define TestExport_h
+
+// classes used outside of the .so, in tests, are declared with this attribute
+#define TEST_EXPORT __attribute__((visibility("default")))
+
+#endif // #define TestExport_h
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 3c262d4..31a0593 100644
--- a/Source/WebCore/platform/graphics/android/TiledPage.cpp
+++ b/Source/WebCore/platform/graphics/android/TiledPage.cpp
@@ -68,6 +68,7 @@ TiledPage::TiledPage(int id, GLWebViewState* state)
, m_latestPictureInval(0)
, m_prepare(false)
, m_isPrefetchPage(false)
+ , m_willDraw(false)
{
m_baseTiles = new BaseTile[TilesManager::getMaxTextureAllocation() + 1];
#ifdef DEBUG_COUNT
@@ -241,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;
@@ -255,26 +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);
-
- m_expandedTileBounds.fLeft = firstTileX;
- m_expandedTileBounds.fTop = firstTileY;
- m_expandedTileBounds.fRight = lastTileX;
- m_expandedTileBounds.fBottom = lastTileY;
+ // 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);
@@ -303,7 +306,22 @@ bool TiledPage::hasMissingContent(const SkIRect& tileBounds)
return neededTiles > 0;
}
-bool TiledPage::swapBuffersIfReady(const SkIRect& tileBounds, float scale, SwapMethod swap)
+bool TiledPage::isReady(const SkIRect& tileBounds)
+{
+ int neededTiles = tileBounds.width() * tileBounds.height();
+ XLOG("tiled page %p needs %d ready tiles", this, neededTiles);
+ for (int j = 0; j < m_baseTileSize; j++) {
+ BaseTile& tile = m_baseTiles[j];
+ if (tileBounds.contains(tile.x(), tile.y())) {
+ if (tile.isTileReady())
+ neededTiles--;
+ }
+ }
+ XLOG("tiled page %p still needs %d ready tiles", this, neededTiles);
+ return neededTiles == 0;
+}
+
+bool TiledPage::swapBuffersIfReady(const SkIRect& tileBounds, float scale)
{
if (!m_glWebViewState)
return false;
@@ -316,21 +334,11 @@ bool TiledPage::swapBuffersIfReady(const SkIRect& tileBounds, float scale, SwapM
int swaps = 0;
bool fullSwap = true;
- if (swap == SwapWholePage) {
- for (int x = tileBounds.fLeft; x < tileBounds.fRight; x++) {
- for (int y = tileBounds.fTop; y < tileBounds.fBottom; y++) {
- BaseTile* t = getBaseTile(x, y);
- if (!t || !t->isTileReady())
- return false;
- }
- }
- } else { // SwapWhateveryIsReady
- for (int x = tileBounds.fLeft; x < tileBounds.fRight; x++) {
- for (int y = tileBounds.fTop; y < tileBounds.fBottom; y++) {
- BaseTile* t = getBaseTile(x, y);
- if (!t || !t->isTileReady())
- fullSwap = false;
- }
+ for (int x = tileBounds.fLeft; x < tileBounds.fRight; x++) {
+ for (int y = tileBounds.fTop; y < tileBounds.fBottom; y++) {
+ BaseTile* t = getBaseTile(x, y);
+ if (!t || !t->isTileReady())
+ fullSwap = false;
}
}
@@ -341,15 +349,20 @@ bool TiledPage::swapBuffersIfReady(const SkIRect& tileBounds, float scale, SwapM
swaps++;
}
- XLOG("%p %s swapped %d textures, returning true",
- this, (swap == SwapWholePage) ? "whole page" : "greedy swap", swaps);
+ XLOG("%p greedy swapped %d textures, returning true", this, swaps);
return fullSwap;
}
+void TiledPage::prepareForDrawGL(float transparency, const SkIRect& tileBounds)
+{
+ m_willDraw = true;
+ m_transparency = transparency;
+ m_tileBounds = tileBounds;
+}
-void TiledPage::draw(float transparency, const SkIRect& tileBounds)
+void TiledPage::drawGL()
{
- if (!m_glWebViewState)
+ if (!m_glWebViewState || m_transparency == 0 || !m_willDraw)
return;
const float tileWidth = TilesManager::tileWidth() * m_invScale;
@@ -357,7 +370,7 @@ void TiledPage::draw(float transparency, const SkIRect& tileBounds)
for (int j = 0; j < m_baseTileSize; j++) {
BaseTile& tile = m_baseTiles[j];
- bool tileInView = tileBounds.contains(tile.x(), tile.y());
+ bool tileInView = m_tileBounds.contains(tile.x(), tile.y());
if (tileInView) {
SkRect rect;
rect.fLeft = tile.x() * tileWidth;
@@ -365,11 +378,12 @@ void TiledPage::draw(float transparency, const SkIRect& tileBounds)
rect.fRight = rect.fLeft + tileWidth;
rect.fBottom = rect.fTop + tileHeight;
- tile.draw(transparency, rect, m_scale);
+ tile.draw(m_transparency, rect, m_scale);
}
TilesManager::instance()->getProfiler()->nextTile(tile, m_invScale, tileInView);
}
+ m_willDraw = false; // don't redraw until re-prepared
}
bool TiledPage::paint(BaseTile* tile, SkCanvas* canvas, unsigned int* pictureUsed)
diff --git a/Source/WebCore/platform/graphics/android/TiledPage.h b/Source/WebCore/platform/graphics/android/TiledPage.h
index 960f3d5..791e1f6 100644
--- a/Source/WebCore/platform/graphics/android/TiledPage.h
+++ b/Source/WebCore/platform/graphics/android/TiledPage.h
@@ -55,10 +55,6 @@ public:
ExpandedBounds = 0,
VisibleBounds = 1
};
- enum SwapMethod {
- SwapWhateverIsReady = 0,
- SwapWholePage = 1
- };
TiledPage(int id, GLWebViewState* state);
~TiledPage();
@@ -76,10 +72,14 @@ public:
// returns true if the page can't draw the entire region (may still be stale)
bool hasMissingContent(const SkIRect& tileBounds);
+ bool isReady(const SkIRect& tileBounds);
+
// swap 'buffers' by swapping each modified texture
- bool swapBuffersIfReady(const SkIRect& tileBounds, float scale, SwapMethod swap);
+ bool swapBuffersIfReady(const SkIRect& tileBounds, float scale);
+ // save the transparency and bounds to be drawn in drawGL()
+ void prepareForDrawGL(float transparency, const SkIRect& tileBounds);
// draw the page on the screen
- void draw(float transparency, const SkIRect& tileBounds);
+ void drawGL();
// TilePainter implementation
// used by individual tiles to generate the bitmap for their tile
@@ -97,7 +97,6 @@ public:
void discardTextures();
void updateBaseTileSize();
bool scrollingDown() { return m_scrollingDown; }
- SkIRect* expandedTileBounds() { return &m_expandedTileBounds; }
bool isPrefetchPage() { return m_isPrefetchPage; }
void setIsPrefetchPage(bool isPrefetch) { m_isPrefetchPage = isPrefetch; }
@@ -128,8 +127,12 @@ private:
unsigned int m_latestPictureInval;
bool m_prepare;
bool m_scrollingDown;
- SkIRect m_expandedTileBounds;
bool m_isPrefetchPage;
+
+ // info saved in prepare, used in drawGL()
+ bool m_willDraw;
+ SkIRect m_tileBounds;
+ float m_transparency;
};
} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/TiledTexture.cpp b/Source/WebCore/platform/graphics/android/TiledTexture.cpp
index e1e5ec9..d538416 100644
--- a/Source/WebCore/platform/graphics/android/TiledTexture.cpp
+++ b/Source/WebCore/platform/graphics/android/TiledTexture.cpp
@@ -32,6 +32,7 @@
#include "PaintedSurface.h"
#include "PaintTileOperation.h"
#include "SkCanvas.h"
+#include "SkPicture.h"
#include <cutils/log.h>
#include <wtf/CurrentTime.h>
@@ -54,7 +55,17 @@
namespace WebCore {
-bool TiledTexture::ready() {
+TiledTexture::~TiledTexture()
+{
+ SkSafeUnref(m_paintingPicture);
+#ifdef DEBUG_COUNT
+ ClassTracker::instance()->decrement("TiledTexture");
+#endif
+ removeTiles();
+}
+
+bool TiledTexture::ready()
+{
bool tilesAllReady = true;
bool tilesVisible = false;
for (unsigned int i = 0; i < m_tiles.size(); i++) {
@@ -71,10 +82,23 @@ bool TiledTexture::ready() {
// in order to unblock the zooming process.
// FIXME: have a better system -- maybe keeping the last scale factor
// able to fully render everything
+ XLOG("TT %p, ready %d, visible %d, texturesRemain %d",
+ this, tilesAllReady, tilesVisible,
+ TilesManager::instance()->layerTexturesRemain());
+
return !TilesManager::instance()->layerTexturesRemain()
|| !tilesVisible || tilesAllReady;
}
+void TiledTexture::swapTiles()
+{
+ int swaps = 0;
+ for (unsigned int i = 0; i < m_tiles.size(); i++)
+ if (m_tiles[i]->swapTexturesIfNeeded())
+ swaps++;
+ XLOG("TT %p swapping, swaps = %d", this, swaps);
+}
+
IntRect TiledTexture::computeTilesArea(IntRect& visibleArea, float scale)
{
IntRect computedArea;
@@ -83,6 +107,8 @@ IntRect TiledTexture::computeTilesArea(IntRect& visibleArea, float scale)
ceilf(visibleArea.width() * scale),
ceilf(visibleArea.height() * scale));
+ XLOG("TT %p prepare, scale %f, area %d x %d", this, scale, area.width(), area.height());
+
if (area.width() == 0 && area.height() == 0) {
computedArea.setWidth(0);
computedArea.setHeight(0);
@@ -102,15 +128,13 @@ IntRect TiledTexture::computeTilesArea(IntRect& visibleArea, float scale)
}
void TiledTexture::prepare(GLWebViewState* state, float scale, bool repaint,
- bool startFastSwap, IntRect& area)
+ bool startFastSwap, IntRect& visibleArea)
{
if (!m_surface)
return;
- if (!m_surface->layer())
- return;
-
- m_area = computeTilesArea(area, scale);
+ // first, how many tiles do we need
+ m_area = computeTilesArea(visibleArea, scale);
if (m_area.isEmpty())
return;
@@ -130,31 +154,6 @@ void TiledTexture::prepare(GLWebViewState* state, float scale, bool repaint,
m_scale = scale;
- // unlock if tiles all ready
- bool tilesAllReady = ready();
-
- // startFastSwap=true will swap all ready tiles each
- // frame until all visible tiles are up to date
- if (tilesAllReady)
- m_swapWhateverIsReady = false;
- else if (startFastSwap)
- m_swapWhateverIsReady = true;
-
- // swap as appropriate
- for (unsigned int i = 0; i < m_tiles.size(); i++) {
- BaseTile* tile = m_tiles[i];
- if (tilesAllReady || m_swapWhateverIsReady)
- tile->swapTexturesIfNeeded();
- }
-
- if (tilesAllReady) {
- m_updateManager.swap();
- m_dirtyRegion.op(m_updateManager.getPaintingInval(), SkRegion::kUnion_Op);
- XLOG("TT %p swapping, now painting with picture %p"
- this, m_updateManager.getPaintingPicture());
- m_updateManager.clearPaintingInval();
- }
-
// apply dirty region to affected tiles
if (!m_dirtyRegion.isEmpty()) {
for (unsigned int i = 0; i < m_tiles.size(); i++) {
@@ -179,12 +178,14 @@ void TiledTexture::prepare(GLWebViewState* state, float scale, bool repaint,
void TiledTexture::update(const SkRegion& invalRegion, SkPicture* picture)
{
- XLOG("TT %p, update manager %p updated with picture %p, region empty %d",
- this, &m_updateManager, picture, invalRegion.isEmpty());
- // attempt to update inval and picture. these may be deferred below instead
- // of used immediately.
- m_updateManager.updateInval(invalRegion);
- m_updateManager.updatePicture(picture);
+ XLOG("TT %p update, current region empty %d, new empty %d, painting picture %p",
+ this, m_dirtyRegion.isEmpty(), invalRegion.isEmpty(), picture);
+ m_dirtyRegion.op(invalRegion, SkRegion::kUnion_Op);
+
+ android::Mutex::Autolock lock(m_paintingPictureSync);
+ SkSafeRef(picture);
+ SkSafeUnref(m_paintingPicture);
+ m_paintingPicture = picture;
}
void TiledTexture::prepareTile(bool repaint, int x, int y)
@@ -195,7 +196,7 @@ void TiledTexture::prepareTile(bool repaint, int x, int y)
m_tiles.append(tile);
}
- XLOG("preparing tile %p, painter is this %p", tile, this);
+ XLOG("preparing tile %p at %d, %d, painter is this %p", tile, x, y, this);
tile->setContents(this, x, y, m_scale);
// TODO: move below (which is largely the same for layers / tiled page) into
@@ -203,8 +204,9 @@ void TiledTexture::prepareTile(bool repaint, int x, int y)
if (tile->isDirty() || !tile->frontTexture())
tile->reserveTexture();
- LayerAndroid* layer = m_surface->layer();
- if (tile->backTexture() && tile->isDirty() && !tile->isRepaintPending() && layer) {
+
+ 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);
TilesManager::instance()->scheduleOperation(operation);
}
@@ -222,12 +224,28 @@ 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
TilesManager::instance()->getTilesTracker()->trackLayer();
#endif
@@ -254,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
@@ -270,11 +288,29 @@ bool TiledTexture::draw()
bool TiledTexture::paint(BaseTile* tile, SkCanvas* canvas, unsigned int* pictureUsed)
{
- return m_updateManager.paint(tile, canvas, pictureUsed);
+ m_paintingPictureSync.lock();
+ SkPicture* picture = m_paintingPicture;
+ SkSafeRef(picture);
+ m_paintingPictureSync.unlock();
+
+ if (!picture) {
+ XLOG("TT %p COULDNT PAINT, NO PICTURE", this);
+ return false;
+ }
+
+ XLOG("TT %p painting tile %d, %d with picture %p", this, tile->x(), tile->y(), picture);
+
+ canvas->drawPicture(*picture);
+
+ SkSafeUnref(picture);
+
+ return true;
}
const TransformationMatrix* TiledTexture::transform()
{
+ if (!m_surface)
+ return 0;
return m_surface->transform();
}
@@ -304,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);
@@ -335,8 +371,8 @@ void DualTiledTexture::prepare(GLWebViewState* state, float scale, bool repaint,
m_zooming = true;
}
- XLOG("\n*** %x Drawing with scale %.2f, futureScale: %.2f, zooming: %d",
- this, scale, m_futureScale, m_zooming);
+ XLOG("Preparing DTT %p with scale %.2f, m_scale %.2f, futureScale: %.2f, zooming: %d",
+ this, scale, m_scale, m_futureScale, m_zooming);
if (m_scale > 0)
m_frontTexture->prepare(state, m_scale, repaint, startFastSwap, m_preZoomVisibleArea);
@@ -345,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;
}
@@ -373,6 +410,12 @@ void DualTiledTexture::update(const SkRegion& dirtyArea, SkPicture* picture)
m_frontTexture->update(dirtyArea, picture);
}
+void DualTiledTexture::swapTiles()
+{
+ m_backTexture->swapTiles();
+ m_frontTexture->swapTiles();
+}
+
bool DualTiledTexture::owns(BaseTileTexture* texture)
{
bool owns = m_textureA->owns(texture);
diff --git a/Source/WebCore/platform/graphics/android/TiledTexture.h b/Source/WebCore/platform/graphics/android/TiledTexture.h
index 5a47cd9..444ab14 100644
--- a/Source/WebCore/platform/graphics/android/TiledTexture.h
+++ b/Source/WebCore/platform/graphics/android/TiledTexture.h
@@ -34,19 +34,16 @@
#include "SkRegion.h"
#include "TextureOwner.h"
#include "TilePainter.h"
-#include "UpdateManager.h"
class SkCanvas;
namespace WebCore {
-class UpdateManager;
-class PaintedSurface;
-
class TiledTexture : public TilePainter {
public:
- TiledTexture(PaintedSurface* surface)
- : m_surface(surface)
+ TiledTexture(SurfacePainter* surface)
+ : m_paintingPicture(0)
+ , m_surface(surface)
, m_prevTileX(0)
, m_prevTileY(0)
, m_scale(1)
@@ -57,18 +54,14 @@ public:
ClassTracker::instance()->increment("TiledTexture");
#endif
}
- virtual ~TiledTexture()
- {
-#ifdef DEBUG_COUNT
- ClassTracker::instance()->decrement("TiledTexture");
-#endif
- removeTiles();
- };
+
+ virtual ~TiledTexture();
IntRect computeTilesArea(IntRect& visibleArea, float scale);
void prepare(GLWebViewState* state, float scale, bool repaint,
bool startFastSwap, IntRect& visibleArea);
+ void swapTiles();
bool draw();
void prepareTile(bool repaint, int x, int y);
@@ -87,16 +80,18 @@ public:
float scale() { return m_scale; }
bool ready();
- PaintedSurface* surface() { return m_surface; }
-
int nbTextures(IntRect& area, float scale);
private:
bool tileIsVisible(BaseTile* tile);
- UpdateManager m_updateManager;
+ // protect m_paintingPicture
+ // update() on UI thread modifies
+ // paint() on texture gen thread reads
+ android::Mutex m_paintingPictureSync;
+ SkPicture* m_paintingPicture;
- PaintedSurface* m_surface;
+ SurfacePainter* m_surface;
Vector<BaseTile*> m_tiles;
// tile coordinates in viewport, set in prepare()
@@ -113,14 +108,19 @@ private:
class DualTiledTexture {
public:
- DualTiledTexture(PaintedSurface* surface);
+ DualTiledTexture(SurfacePainter* surface);
~DualTiledTexture();
void prepare(GLWebViewState* state, float scale, bool repaint,
bool startFastSwap, IntRect& area);
+ void swapTiles();
void swap();
bool draw();
void update(const SkRegion& dirtyArea, SkPicture* picture);
bool owns(BaseTileTexture* texture);
+ bool isReady()
+ {
+ return !m_zooming && m_frontTexture->ready();
+ }
int nbTextures(IntRect& area, float scale)
{
diff --git a/Source/WebCore/platform/graphics/android/TilesManager.cpp b/Source/WebCore/platform/graphics/android/TilesManager.cpp
index acfe9e7..30bd8d0 100644
--- a/Source/WebCore/platform/graphics/android/TilesManager.cpp
+++ b/Source/WebCore/platform/graphics/android/TilesManager.cpp
@@ -69,7 +69,7 @@
// number to cap the layer tile texturs, it worked on both phones and tablets.
// TODO: after merge the pool of base tiles and layer tiles, we should revisit
// the logic of allocation management.
-#define MAX_TEXTURE_ALLOCATION ((6+TILE_PREFETCH_DISTANCE*2)*(5+TILE_PREFETCH_DISTANCE*2)*2)
+#define MAX_TEXTURE_ALLOCATION ((6+TILE_PREFETCH_DISTANCE*2)*(5+TILE_PREFETCH_DISTANCE*2)*4)
#define TILE_WIDTH 256
#define TILE_HEIGHT 256
#define LAYER_TILE_WIDTH 256
@@ -77,6 +77,8 @@
#define BYTES_PER_PIXEL 4 // 8888 config
+#define LAYER_TEXTURES_DESTROY_TIMEOUT 60 // If we do not need layers for 60 seconds, free the textures
+
namespace WebCore {
GLint TilesManager::getMaxTextureSize()
@@ -95,12 +97,15 @@ int TilesManager::getMaxTextureAllocation()
TilesManager::TilesManager()
: m_layerTexturesRemain(true)
, m_maxTextureCount(0)
+ , m_maxLayerTextureCount(0)
, m_generatorReady(false)
, m_showVisualIndicator(false)
, m_invertedScreen(false)
, m_invertedScreenSwitch(false)
, m_useMinimalMemory(true)
, m_drawGLCount(1)
+ , m_lastTimeLayersUsed(0)
+ , m_hasLayerTextures(false)
{
XLOG("TilesManager ctor");
m_textures.reserveCapacity(MAX_TEXTURE_ALLOCATION);
@@ -128,9 +133,9 @@ void TilesManager::allocateTiles()
nbTexturesAllocated++;
}
- int nbLayersTexturesToAllocate = m_maxTextureCount - m_tilesTextures.size();
+ int nbLayersTexturesToAllocate = m_maxLayerTextureCount - m_tilesTextures.size();
XLOG("%d layers tiles to allocate (%d textures planned)",
- nbLayersTexturesToAllocate, m_maxTextureCount);
+ nbLayersTexturesToAllocate, m_maxLayerTextureCount);
int nbLayersTexturesAllocated = 0;
for (int i = 0; i < nbLayersTexturesToAllocate; i++) {
BaseTileTexture* texture = new BaseTileTexture(
@@ -153,7 +158,6 @@ void TilesManager::allocateTiles()
void TilesManager::deallocateTextures(bool allTextures)
{
const unsigned int max = m_textures.size();
- const unsigned int maxLayer = m_tilesTextures.size();
unsigned long long sparedDrawCount = ~0; // by default, spare no textures
if (!allTextures) {
@@ -165,19 +169,19 @@ void TilesManager::deallocateTextures(bool allTextures)
sparedDrawCount = std::max(sparedDrawCount, owner->drawCount());
}
}
+ deallocateTexturesVector(sparedDrawCount, m_textures);
+ deallocateTexturesVector(sparedDrawCount, m_tilesTextures);
+}
+void TilesManager::deallocateTexturesVector(unsigned long long sparedDrawCount,
+ WTF::Vector<BaseTileTexture*>& textures)
+{
+ const unsigned int max = textures.size();
int dealloc = 0;
for (unsigned int i = 0; i < max; i++) {
- TextureOwner* owner = m_textures[i]->owner();
+ TextureOwner* owner = textures[i]->owner();
if (!owner || owner->drawCount() < sparedDrawCount) {
- m_textures[i]->discardGLTexture();
- dealloc++;
- }
- }
- for (unsigned int i = 0; i < maxLayer; i++) {
- TextureOwner* owner = m_tilesTextures[i]->owner();
- if (!owner || owner->drawCount() < sparedDrawCount) {
- m_tilesTextures[i]->discardGLTexture();
+ textures[i]->discardGLTexture();
dealloc++;
}
}
@@ -185,6 +189,23 @@ void TilesManager::deallocateTextures(bool allTextures)
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
@@ -208,21 +229,6 @@ void TilesManager::printTextures()
#endif // DEBUG
}
-void TilesManager::swapLayersTextures(LayerAndroid* oldTree, LayerAndroid* newTree)
-{
- if (oldTree)
- oldTree->assignTextureTo(newTree);
-
- if (newTree)
- newTree->createTexture();
-
- GLWebViewState* oldState = 0;
- if (oldTree && !newTree)
- oldState = oldTree->state();
-
- paintedSurfacesCleanup(oldState);
-}
-
void TilesManager::addPaintedSurface(PaintedSurface* surface)
{
m_paintedSurfaces.append(surface);
@@ -352,6 +358,12 @@ int TilesManager::maxTextureCount()
return m_maxTextureCount;
}
+int TilesManager::maxLayerTextureCount()
+{
+ android::Mutex::Autolock lock(m_texturesLock);
+ return m_maxLayerTextureCount;
+}
+
void TilesManager::setMaxTextureCount(int max)
{
XLOG("setMaxTextureCount: %d (current: %d, total:%d)",
@@ -370,6 +382,36 @@ void TilesManager::setMaxTextureCount(int max)
allocateTiles();
}
+void TilesManager::setMaxLayerTextureCount(int max)
+{
+ XLOG("setMaxLayerTextureCount: %d (current: %d, total:%d)",
+ max, m_maxLayerTextureCount, MAX_TEXTURE_ALLOCATION);
+ if (!max && m_hasLayerTextures) {
+ double secondsSinceLayersUsed = WTF::currentTime() - m_lastTimeLayersUsed;
+ if (secondsSinceLayersUsed > LAYER_TEXTURES_DESTROY_TIMEOUT) {
+ unsigned long long sparedDrawCount = ~0; // by default, spare no textures
+ deallocateTexturesVector(sparedDrawCount, m_tilesTextures);
+ m_hasLayerTextures = false;
+ }
+ return;
+ }
+ m_lastTimeLayersUsed = WTF::currentTime();
+ if (m_maxLayerTextureCount == MAX_TEXTURE_ALLOCATION ||
+ max <= m_maxLayerTextureCount)
+ return;
+
+ android::Mutex::Autolock lock(m_texturesLock);
+
+ if (max < MAX_TEXTURE_ALLOCATION)
+ m_maxLayerTextureCount = max;
+ else
+ m_maxLayerTextureCount = MAX_TEXTURE_ALLOCATION;
+
+ allocateTiles();
+ m_hasLayerTextures = true;
+}
+
+
float TilesManager::tileWidth()
{
return TILE_WIDTH;
@@ -412,13 +454,24 @@ void TilesManager::paintedSurfacesCleanup(GLWebViewState* state)
WTF::Vector<PaintedSurface*> collect;
for (unsigned int i = 0; i < m_paintedSurfaces.size(); i++) {
PaintedSurface* surface = m_paintedSurfaces[i];
- if (!surface->layer() || (state && surface->layer()->state() == state))
+
+ Layer* drawing = surface->drawingLayer();
+ Layer* painting = surface->paintingLayer();
+
+ XLOG("considering PS %p, drawing %p, painting %p", surface, drawing, painting);
+
+ bool drawingMatchesState = state && drawing && (drawing->state() == state);
+ bool paintingMatchesState = state && painting && (painting->state() == state);
+
+ if ((!painting && !drawing) || drawingMatchesState || paintingMatchesState) {
+ XLOG("trying to remove PS %p, painting %p, drawing %p, DMS %d, PMS %d",
+ surface, painting, drawing, drawingMatchesState, paintingMatchesState);
collect.append(surface);
+ }
}
for (unsigned int i = 0; i < collect.size(); i++) {
PaintedSurface* surface = collect[i];
m_paintedSurfaces.remove(m_paintedSurfaces.find(surface));
- surface->removeLayer();
SkSafeUnref(surface);
}
}
diff --git a/Source/WebCore/platform/graphics/android/TilesManager.h b/Source/WebCore/platform/graphics/android/TilesManager.h
index 8ae9202..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);
@@ -105,12 +107,14 @@ public:
void resetTextureUsage(TiledPage* page);
int maxTextureCount();
+ int maxLayerTextureCount();
void setMaxTextureCount(int max);
+ void setMaxLayerTextureCount(int max);
static float tileWidth();
static float tileHeight();
static float layerTileWidth();
static float layerTileHeight();
- void paintedSurfacesCleanup(GLWebViewState* state);
+ void paintedSurfacesCleanup(GLWebViewState* state = 0);
void unregisterGLWebViewState(GLWebViewState* state);
void allocateTiles();
@@ -190,6 +194,11 @@ public:
return m_drawGLCount;
}
+ int getPaintedSurfaceCount()
+ {
+ return m_paintedSurfaces.size();
+ }
+
private:
TilesManager();
@@ -200,6 +209,9 @@ private:
m_generatorReadyCond.wait(m_generatorLock);
}
+ void deallocateTexturesVector(unsigned long long sparedDrawCount,
+ WTF::Vector<BaseTileTexture*>& textures);
+
Vector<BaseTileTexture*> m_textures;
Vector<BaseTileTexture*> m_availableTextures;
@@ -210,6 +222,7 @@ private:
Vector<PaintedSurface*> m_paintedSurfaces;
int m_maxTextureCount;
+ int m_maxLayerTextureCount;
bool m_generatorReady;
@@ -235,6 +248,8 @@ private:
TilesProfiler m_profiler;
TilesTracker m_tilesTracker;
unsigned long long m_drawGLCount;
+ double m_lastTimeLayersUsed;
+ bool m_hasLayerTextures;
};
} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/TransferQueue.cpp b/Source/WebCore/platform/graphics/android/TransferQueue.cpp
index 5c4f0f3..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
@@ -297,8 +297,11 @@ void TransferQueue::updateDirtyBaseTiles()
BaseTileTexture* destTexture = 0;
if (!obsoleteBaseTile)
destTexture = m_transferQueue[index].savedBaseTilePtr->backTexture();
- if (m_transferQueue[index].uploadType == GpuUpload)
- m_sharedSurfaceTexture->updateTexImage();
+ if (m_transferQueue[index].uploadType == GpuUpload) {
+ status_t result = m_sharedSurfaceTexture->updateTexImage();
+ if (result != OK)
+ XLOGC("unexpected error: updateTexImage return %d", result);
+ }
m_transferQueue[index].savedBaseTilePtr = 0;
m_transferQueue[index].status = emptyItem;
if (obsoleteBaseTile) {
@@ -491,8 +494,11 @@ void TransferQueue::cleanupTransportQueue()
// No matter what the current upload type is, as long as there has
// been a Surf Tex enqueue operation, this updateTexImage need to
// be called to keep things in sync.
- if (m_transferQueue[index].uploadType == GpuUpload)
- m_sharedSurfaceTexture->updateTexImage();
+ if (m_transferQueue[index].uploadType == GpuUpload) {
+ status_t result = m_sharedSurfaceTexture->updateTexImage();
+ if (result != OK)
+ XLOGC("unexpected error: updateTexImage return %d", result);
+ }
// since tiles in the queue may be from another webview, remove
// their textures so that they will be repainted / retransferred
diff --git a/Source/WebCore/platform/graphics/android/TreeManager.cpp b/Source/WebCore/platform/graphics/android/TreeManager.cpp
new file mode 100644
index 0000000..b7eaacf
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/TreeManager.cpp
@@ -0,0 +1,331 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "TreeManager.h"
+
+#include "Layer.h"
+#include "BaseLayerAndroid.h"
+#include "ScrollableLayerAndroid.h"
+#include "TilesManager.h"
+
+#include <cutils/log.h>
+#include <wtf/CurrentTime.h>
+#include <wtf/text/CString.h>
+
+#undef XLOGC
+#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "TreeManager", __VA_ARGS__)
+
+#ifdef DEBUG
+
+#undef XLOG
+#define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "TreeManager", __VA_ARGS__)
+
+#else
+
+#undef XLOG
+#define XLOG(...)
+
+#endif // DEBUG
+
+namespace WebCore {
+
+TreeManager::TreeManager()
+ : m_drawingTree(0)
+ , m_paintingTree(0)
+ , m_queuedTree(0)
+ , m_fastSwapMode(false)
+{
+}
+
+TreeManager::~TreeManager()
+{
+ clearTrees();
+}
+
+// the painting tree has finished painting:
+// discard the drawing tree
+// swap the painting tree in place of the drawing tree
+// and start painting the queued tree
+void TreeManager::swap()
+{
+ // swap can't be called unless painting just finished
+ ASSERT(m_paintingTree);
+
+ android::Mutex::Autolock lock(m_paintSwapLock);
+
+ XLOG("SWAPPING, D %p, P %p, Q %p", m_drawingTree, m_paintingTree, m_queuedTree);
+
+ // if we have a drawing tree, discard it since the painting tree is done
+ if (m_drawingTree) {
+ XLOG("destroying drawing tree %p", m_drawingTree);
+ m_drawingTree->setIsDrawing(false);
+ SkSafeUnref(m_drawingTree);
+ }
+
+ // 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
+ XLOG("now painting tree %p", m_queuedTree);
+ m_queuedTree->setIsPainting(m_paintingTree);
+ }
+ m_drawingTree = m_paintingTree;
+ m_paintingTree = m_queuedTree;
+ m_queuedTree = 0;
+
+ TilesManager::instance()->paintedSurfacesCleanup();
+
+ XLOG("SWAPPING COMPLETE, D %p, P %p, Q %p", m_drawingTree, m_paintingTree, m_queuedTree);
+}
+
+// clear all of the content in the three trees held by the tree manager
+void TreeManager::clearTrees()
+{
+ // remove painted surfaces from any tree in this view, and set trees as no
+ // longer drawing, to clear ptrs from surfaces to layers
+ GLWebViewState* oldState = 0;
+ if (m_drawingTree) {
+ oldState = m_drawingTree->state();
+ m_drawingTree->setIsDrawing(false);
+ }
+ if (m_paintingTree) {
+ oldState = m_paintingTree->state();
+ m_paintingTree->setIsDrawing(false);
+ }
+
+ XLOG("TreeManager %p removing PS from state %p", this, oldState);
+ TilesManager::instance()->paintedSurfacesCleanup(oldState);
+
+ SkSafeUnref(m_drawingTree);
+ m_drawingTree = 0;
+ SkSafeUnref(m_paintingTree);
+ m_paintingTree = 0;
+ SkSafeUnref(m_queuedTree);
+ m_queuedTree = 0;
+}
+
+// a new layer tree has arrived, queue it if we're painting something already,
+// 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);
+
+ SkSafeRef(newTree);
+
+ android::Mutex::Autolock lock(m_paintSwapLock);
+
+ if (!newTree || brandNew) {
+ clearTrees();
+ if (brandNew) {
+ m_paintingTree = newTree;
+ m_paintingTree->setIsPainting(m_drawingTree);
+ }
+ return;
+ }
+
+ if (m_queuedTree || m_paintingTree) {
+ // currently painting, so defer this new tree
+ if (m_queuedTree) {
+ // 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;
+ return;
+ }
+
+ // don't have painting tree, paint this one!
+ m_paintingTree = newTree;
+ 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* treesSwappedPtr, bool* newTreeHasAnimPtr,
+ TexturesResult* texturesResultPtr)
+{
+ m_fastSwapMode |= enterFastSwapMode;
+
+ XLOG("drawGL, D %p, P %p, Q %p, fastSwap %d",
+ m_drawingTree, m_paintingTree, m_queuedTree, m_fastSwapMode);
+
+ 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 (laTree)
+ laTree->computeTexturesAmount(texturesResultPtr);
+
+ if (/*!m_fastSwapMode && */ m_paintingTree->isReady()) {
+ XLOG("have painting tree %p ready, swapping!", m_paintingTree);
+ didTreeSwap = true;
+ swap();
+ if (treesSwappedPtr)
+ *treesSwappedPtr = true;
+ if (laTree && newTreeHasAnimPtr)
+ *newTreeHasAnimPtr = laTree->hasAnimations();
+ }
+ } else if (m_drawingTree) {
+ XLOG("preparing drawing tree %p", m_drawingTree);
+ ret |= m_drawingTree->prepare(currentTime, viewRect,
+ visibleRect, scale);
+ if (m_drawingTree->countChildren()) {
+ LayerAndroid* laTree = static_cast<LayerAndroid*>(m_drawingTree->getChild(0));
+ laTree->computeTexturesAmount(texturesResultPtr);
+ }
+ }
+
+
+ if (m_drawingTree) {
+ bool drawingReady = didTreeSwap || m_drawingTree->isReady();
+
+ if (didTreeSwap || m_fastSwapMode || (drawingReady && !m_paintingTree))
+ m_drawingTree->swapTiles();
+
+ if (drawingReady) {
+ // exit fast swap mode, as content is up to date
+ m_fastSwapMode = false;
+ } else {
+ // drawing isn't ready, must redraw
+ ret = true;
+ }
+
+ if (m_drawingTree->countChildren()) {
+ LayerAndroid* laTree = static_cast<LayerAndroid*>(m_drawingTree->getChild(0));
+ ret |= laTree->evaluateAnimations(currentTime);
+ }
+ XLOG("drawing tree %p", m_drawingTree);
+ ret |= m_drawingTree->drawGL(viewRect, visibleRect, scale);
+ } else if (m_paintingTree && m_paintingTree->state()) {
+ // Dont have a drawing tree, draw white background
+ Color defaultBackground = Color::white;
+ m_paintingTree->state()->drawBackground(defaultBackground);
+ }
+
+ if (m_paintingTree) {
+ XLOG("still have painting tree %p", m_paintingTree);
+ return true;
+ }
+
+ return ret;
+}
+
+int TreeManager::getTotalPaintedSurfaceCount()
+{
+ return TilesManager::instance()->getPaintedSurfaceCount();
+}
+
+// draw for base tile - called on TextureGeneration thread
+void TreeManager::drawCanvas(SkCanvas* canvas, bool drawLayers)
+{
+ BaseLayerAndroid* paintingTree = 0;
+ m_paintSwapLock.lock();
+ if (m_paintingTree)
+ paintingTree = static_cast<BaseLayerAndroid*>(m_paintingTree);
+ else
+ paintingTree = static_cast<BaseLayerAndroid*>(m_drawingTree);
+ SkSafeRef(paintingTree);
+ m_paintSwapLock.unlock();
+
+ if (!paintingTree)
+ return;
+
+
+ paintingTree->drawCanvas(canvas);
+
+ if (drawLayers && paintingTree->countChildren()) {
+ // draw the layers onto the canvas as well
+ Layer* layers = paintingTree->getChild(0);
+ static_cast<LayerAndroid*>(layers)->drawCanvas(canvas);
+ }
+
+ SkSafeUnref(paintingTree);
+}
+
+int TreeManager::baseContentWidth()
+{
+ if (m_paintingTree) {
+ return static_cast<BaseLayerAndroid*>(m_paintingTree)->content()->width();
+ } else if (m_drawingTree) {
+ return static_cast<BaseLayerAndroid*>(m_drawingTree)->content()->width();
+ }
+ return 0;
+}
+
+int TreeManager::baseContentHeight()
+{
+ if (m_paintingTree) {
+ return static_cast<BaseLayerAndroid*>(m_paintingTree)->content()->height();
+ } else if (m_drawingTree) {
+ return static_cast<BaseLayerAndroid*>(m_drawingTree)->content()->height();
+ }
+ return 0;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/UpdateManager.h b/Source/WebCore/platform/graphics/android/TreeManager.h
index 6254184..83d5300 100644
--- a/Source/WebCore/platform/graphics/android/UpdateManager.h
+++ b/Source/WebCore/platform/graphics/android/TreeManager.h
@@ -23,65 +23,61 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef UpdateManager_h
-#define UpdateManager_h
+#ifndef TreeManager_h
+#define TreeManager_h
+#include "TestExport.h"
+#include <utils/threads.h>
+#include "PerformanceMonitor.h"
+
+class Layer;
+class SkRect;
class SkCanvas;
-class SkRegion;
namespace WebCore {
-class BaseTile;
-
-// UpdateManager Architecture
+class IntRect;
+class TexturesResult;
-// The UpdateManager is used to defer updates and invalidations to a layer,
-// so that the layer can finish painting one version completely without being
-// interrupted by new invals/content
-
-class UpdateManager {
+class TEST_EXPORT TreeManager {
public:
- UpdateManager();
+ TreeManager();
- ~UpdateManager();
+ ~TreeManager();
- // swap deferred members in place of painting members
- void swap();
+ void updateWithTree(Layer* tree, bool brandNew);
- void updateInval(const SkRegion& invalRegion);
+ void updateScrollableLayer(int layerId, int x, int y);
- void updatePicture(SkPicture* picture);
+ bool drawGL(double currentTime, IntRect& viewRect,
+ SkRect& visibleRect, float scale,
+ bool enterFastSwapMode, bool* treesSwappedPtr, bool* newTreeHasAnimPtr,
+ TexturesResult* texturesResultPtr);
- bool paint(BaseTile* tile, SkCanvas* canvas, unsigned int* pictureUsed);
+ void drawCanvas(SkCanvas* canvas, bool drawLayers);
- void clearPaintingInval();
+ // used in debugging (to avoid exporting TilesManager symbols)
+ static int getTotalPaintedSurfaceCount();
- const SkRegion& getPaintingInval() {
- return m_paintingInval;
- }
-
- SkPicture* getPaintingPicture() {
- // NOTE: only modified on UI thread, so UI thread access doesn't need mutex
- return m_paintingPicture;
- }
+ int baseContentWidth();
+ int baseContentHeight();
private:
- // protect m_paintingPicture
- // swap() on UI thread modifies
- // paint() on texture gen thread reads
- android::Mutex m_paintingPictureSync;
- SkPicture* m_paintingPicture;
+ static void updateScrollableLayerInTree(Layer* tree, int layerId, int x, int y);
+
+ void swap();
+ void clearTrees();
- // inval region to be redrawn with the current paintingPicture
- SkRegion m_paintingInval;
+ android::Mutex m_paintSwapLock;
- // most recently received picture, moved into painting on swap()
- SkPicture* m_deferredPicture;
+ Layer* m_drawingTree;
+ Layer* m_paintingTree;
+ Layer* m_queuedTree;
- // all invals since last swap(), merged with painting inval on swap()
- SkRegion m_deferredInval;
+ bool m_fastSwapMode;
+ PerformanceMonitor m_perf;
};
} // namespace WebCore
-#endif //#define UpdateManager_h
+#endif //#define TreeManager_h
diff --git a/Source/WebCore/platform/graphics/android/UpdateManager.cpp b/Source/WebCore/platform/graphics/android/UpdateManager.cpp
deleted file mode 100644
index 1c20f1f..0000000
--- a/Source/WebCore/platform/graphics/android/UpdateManager.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2011, The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "PaintedSurface.h"
-
-#include "LayerAndroid.h"
-#include "TilesManager.h"
-#include "SkCanvas.h"
-#include "SkPicture.h"
-
-#include <cutils/log.h>
-#include <wtf/CurrentTime.h>
-#include <wtf/text/CString.h>
-
-#undef XLOGC
-#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "UpdateManager", __VA_ARGS__)
-
-#ifdef DEBUG
-
-#undef XLOG
-#define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "UpdateManager", __VA_ARGS__)
-
-#else
-
-#undef XLOG
-#define XLOG(...)
-
-#endif // DEBUG
-
-namespace WebCore {
-
-UpdateManager::UpdateManager()
- : m_paintingPicture(0)
- , m_deferredPicture(0)
-{
-}
-
-UpdateManager::~UpdateManager()
-{
- SkSafeUnref(m_paintingPicture);
- SkSafeUnref(m_deferredPicture);
-}
-
-void UpdateManager::swap()
-{
- m_paintingInval.op(m_deferredInval, SkRegion::kUnion_Op);
- m_deferredInval.setEmpty();
-
- android::Mutex::Autolock lock(m_paintingPictureSync);
- if (m_deferredPicture) {
- XLOG("unlock of updatemanager %p, was painting %p, now painting %p",
- this, m_paintingPicture, m_deferredPicture);
- SkSafeUnref(m_paintingPicture);
- m_paintingPicture = m_deferredPicture;
- m_deferredPicture = 0;
- }
-}
-
-void UpdateManager::updateInval(const SkRegion& invalRegion)
-{
- m_deferredInval.op(invalRegion, SkRegion::kUnion_Op);
-}
-
-void UpdateManager::updatePicture(SkPicture* picture)
-{
- SkSafeRef(picture);
- SkSafeUnref(m_deferredPicture);
- m_deferredPicture = picture;
-}
-
-bool UpdateManager::paint(BaseTile* tile, SkCanvas* canvas, unsigned int* pictureUsed)
-{
- m_paintingPictureSync.lock();
- SkPicture* picture = m_paintingPicture;
- SkSafeRef(picture);
- m_paintingPictureSync.unlock();
-
- XLOG("UpdateManager %p painting with picture %p", this, picture);
-
- if (!picture)
- return false;
-
- canvas->drawPicture(*picture);
-
- // TODO: visualization layer diagonals
-
- SkSafeUnref(picture);
- return true;
-}
-
-
-void UpdateManager::clearPaintingInval()
-{
- m_paintingInval.setEmpty();
-}
-
-} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/VideoLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/VideoLayerAndroid.cpp
index 9576ed1..482d711 100644
--- a/Source/WebCore/platform/graphics/android/VideoLayerAndroid.cpp
+++ b/Source/WebCore/platform/graphics/android/VideoLayerAndroid.cpp
@@ -142,7 +142,7 @@ GLuint VideoLayerAndroid::createBackgroundTexture()
return texture;
}
-bool VideoLayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix)
+bool VideoLayerAndroid::drawGL()
{
// Lazily allocated the textures.
if (!m_createdTexture) {
@@ -224,7 +224,7 @@ bool VideoLayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix)
}
}
- return drawChildrenGL(glWebViewState, matrix);
+ return drawChildrenGL();
}
}
diff --git a/Source/WebCore/platform/graphics/android/VideoLayerAndroid.h b/Source/WebCore/platform/graphics/android/VideoLayerAndroid.h
index abc1c13..8a064bb 100644
--- a/Source/WebCore/platform/graphics/android/VideoLayerAndroid.h
+++ b/Source/WebCore/platform/graphics/android/VideoLayerAndroid.h
@@ -56,7 +56,7 @@ public:
virtual LayerAndroid* copy() const { return new VideoLayerAndroid(*this); }
// The following 3 functions are called in UI thread only.
- virtual bool drawGL(GLWebViewState*, SkMatrix& matrix);
+ virtual bool drawGL();
void setSurfaceTexture(sp<SurfaceTexture> texture, int textureName, PlayerState playerState);
GLuint createBackgroundTexture();
GLuint createSpinnerOuterTexture();
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/RenderHTMLCanvas.cpp b/Source/WebCore/rendering/RenderHTMLCanvas.cpp
index de2a2c1..ada79e9 100644
--- a/Source/WebCore/rendering/RenderHTMLCanvas.cpp
+++ b/Source/WebCore/rendering/RenderHTMLCanvas.cpp
@@ -47,9 +47,13 @@ RenderHTMLCanvas::RenderHTMLCanvas(HTMLCanvasElement* element)
bool RenderHTMLCanvas::requiresLayer() const
{
+#if PLATFORM(ANDROID)
+ return true;
+#endif
+
if (RenderReplaced::requiresLayer())
return true;
-
+
HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(node());
return canvas && canvas->renderingContext() && canvas->renderingContext()->isAccelerated();
}
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 4f4f553..06fa0f6 100644
--- a/Source/WebCore/rendering/RenderLayerCompositor.cpp
+++ b/Source/WebCore/rendering/RenderLayerCompositor.cpp
@@ -650,7 +650,7 @@ bool RenderLayerCompositor::checkForFixedLayers(Vector<RenderLayer*>* list, bool
IntRect bounds = aLayer->renderer()->localToAbsoluteQuad(
FloatRect(aLayer->localBoundingBox())).enclosingBoundingBox();
if (bounds.contains(currentLayerBounds)
- && needsToBeComposited(aLayer)) {
+ && needsToBeComposited(aLayer) && aLayer->isStackingContext()) {
needComposite = false;
break;
}
@@ -724,15 +724,7 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O
if (layer->isFixed())
compositingState.m_hasFixedElement = true;
#endif
-
-#if ENABLE(ANDROID_OVERFLOW_SCROLL)
- // we don't want to signal that the subtree is compositing if the reason
- // is because the layer is an overflow layer -- doing so would trigger
- // all the above layers to be composited unnecessarily
- if (willBeComposited && !layer->hasOverflowScroll() && !layer->isFixed()) {
-#else
if (willBeComposited) {
-#endif
// Tell the parent it has compositing descendants.
compositingState.m_subtreeIsCompositing = true;
// This layer now acts as the ancestor for kids.
@@ -764,7 +756,18 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O
// If we have to make a layer for this child, make one now so we can have a contents layer
// (since we need to ensure that the -ve z-order child renders underneath our contents).
+#ifdef ANDROID
+ // Normally we try to reduce the number of layers by not promoting all fixed
+ // or scrollable elements to their own compositing layer. But in the case that
+ // we have such an element in the negative z-order, we must make it a layer
+ // otherwise the content will be painted at a higher z-index. This breaks pages
+ // that set a large image with a z-index of -1 to implement a background image,
+ // for example.
+ bool childRequiresCompositing = childState.m_hasFixedElement || childState.m_hasScrollableElement;
+ if (!willBeComposited && (childState.m_subtreeIsCompositing || childRequiresCompositing)) {
+#else
if (!willBeComposited && childState.m_subtreeIsCompositing) {
+#endif
// make layer compositing
layer->setMustOverlapCompositedLayers(true);
childState.m_compositingAncestor = layer;
@@ -1381,6 +1384,8 @@ bool RenderLayerCompositor::requiresCompositingForAndroidLayers(const RenderLaye
if (layer->isFixed())
return true;
#endif
+ if (layer->renderer()->isCanvas())
+ return true;
return false;
}
#endif
@@ -1573,7 +1578,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;
diff --git a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp
index bc550a6..bb34652 100644
--- a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp
+++ b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp
@@ -573,11 +573,18 @@ void SVGInlineTextBox::paintDecorationWithStyle(GraphicsContext* context, ETextD
width *= scalingFactor;
decorationOrigin.scale(scalingFactor, scalingFactor);
+#if PLATFORM(ANDROID)
+ // Android does not support GraphicsContext::setCTM().
+ AffineTransform scaleTransform;
+ scaleTransform.scale(1 / scalingFactor);
+ context->concatCTM(scaleTransform);
+#else
AffineTransform newTransform = context->getCTM();
newTransform.scale(1 / scalingFactor);
normalizeTransform(newTransform);
context->setCTM(newTransform);
+#endif
}
decorationOrigin.move(0, -scaledFontMetrics.floatAscent() + positionOffsetForDecoration(decoration, scaledFontMetrics, thickness));
@@ -622,6 +629,13 @@ void SVGInlineTextBox::paintTextWithShadows(GraphicsContext* context, RenderStyl
AffineTransform originalTransform;
if (scalingFactor != 1) {
+#if PLATFORM(ANDROID)
+ // Android does not support GraphicsContext::setCTM().
+ context->save();
+ AffineTransform scaleTransform;
+ scaleTransform.scale(1 / scalingFactor);
+ context->concatCTM(scaleTransform);
+#else
originalTransform = context->getCTM();
AffineTransform newTransform = originalTransform;
@@ -629,12 +643,18 @@ void SVGInlineTextBox::paintTextWithShadows(GraphicsContext* context, RenderStyl
normalizeTransform(newTransform);
context->setCTM(newTransform);
+#endif
}
scaledFont.drawText(context, textRun, textOrigin + extraOffset, startPosition, endPosition);
if (scalingFactor != 1)
+#if PLATFORM(ANDROID)
+ // Android does not support GraphicsContext::setCTM().
+ context->restore();
+#else
context->setCTM(originalTransform);
+#endif
restoreGraphicsContextAfterTextPainting(context, textRun);
diff --git a/Source/WebCore/tests/Android.mk b/Source/WebCore/tests/Android.mk
new file mode 100644
index 0000000..c98a9a3
--- /dev/null
+++ b/Source/WebCore/tests/Android.mk
@@ -0,0 +1,49 @@
+# Build the unit tests.
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# Build the unit tests.
+test_src_files := \
+ TreeManager_test.cpp
+
+shared_libraries := \
+ libcutils \
+ libwebcore \
+ libskia \
+ libstlport
+
+static_libraries := \
+ libgtest \
+ libgtest_main
+
+c_includes := \
+ bionic \
+ bionic/libstdc++/include \
+ external/gtest/include \
+ external/stlport/stlport \
+ external/skia/include/core \
+ external/icu4c/common \
+ $(LOCAL_PATH)/../../JavaScriptCore \
+ $(LOCAL_PATH)/../../JavaScriptCore/wtf \
+ $(LOCAL_PATH)/.. \
+ $(LOCAL_PATH)/../platform/graphics \
+ $(LOCAL_PATH)/../platform/graphics/transforms \
+ $(LOCAL_PATH)/../platform/graphics/android
+
+ # external/webkit/Source/WebCore/platform/graphics/android
+
+module_tags := eng tests
+
+$(foreach file,$(test_src_files), \
+ $(eval include $(CLEAR_VARS)) \
+ $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
+ $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
+ $(eval LOCAL_C_INCLUDES := $(c_includes)) \
+ $(eval LOCAL_SRC_FILES := $(file)) \
+ $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
+ $(eval LOCAL_MODULE_TAGS := $(module_tags)) \
+ $(eval include $(BUILD_EXECUTABLE)) \
+)
+
+# Build the manual test programs.
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/Source/WebCore/tests/TreeManager_test.cpp b/Source/WebCore/tests/TreeManager_test.cpp
new file mode 100644
index 0000000..3837627
--- /dev/null
+++ b/Source/WebCore/tests/TreeManager_test.cpp
@@ -0,0 +1,407 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <gtest/gtest.h>
+
+#include "SkRefCnt.h"
+#include "TransformationMatrix.h"
+#include "IntRect.h"
+#include "Layer.h"
+#include "LayerAndroid.h"
+#include "TreeManager.h"
+#include "SkPicture.h"
+
+#include <cutils/log.h>
+#include <wtf/text/CString.h>
+#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "TreeManager_test", __VA_ARGS__)
+
+namespace WebCore {
+
+// Used for testing simple cases for tree painting, drawing, swapping
+class TestLayer : public Layer {
+public:
+ TestLayer()
+ : m_isDrawing(false)
+ , m_isPainting(false)
+ , m_isDonePainting(false)
+ , m_drawCount(0)
+ {}
+
+ bool m_isDrawing;
+ bool m_isPainting;
+ bool m_isDonePainting;
+ double m_drawCount;
+
+ bool drawGL(WebCore::IntRect& viewRect, SkRect& visibleRect, float scale) {
+ m_drawCount++;
+ return false;
+ }
+
+ bool isReady() {
+ return m_isDonePainting;
+ }
+
+ void setIsDrawing(bool isDrawing) {
+ m_isDrawing = isDrawing;
+ if (isDrawing)
+ m_isPainting = false;
+ }
+
+ void setIsPainting(Layer* drawingTree) {
+ m_isPainting = true;
+ m_isDonePainting = false;
+ setIsDrawing(false);
+ }
+};
+
+// Used for testing complex trees, and painted surfaces
+class TestLayerAndroid : public LayerAndroid {
+public:
+ TestLayerAndroid(SkPicture* picture) : LayerAndroid(picture)
+ , m_isDonePainting(false)
+ , m_drawCount(0)
+ {}
+
+ TestLayerAndroid(const TestLayerAndroid& testLayer) : LayerAndroid(testLayer)
+ , m_isDonePainting(testLayer.m_isDonePainting)
+ , m_drawCount(testLayer.m_drawCount)
+ {
+ XLOGC("copying TLA %p as %p", &testLayer, this);
+ }
+
+ bool m_isDonePainting;
+ double m_drawCount;
+
+ bool drawGL(WebCore::IntRect& viewRect, SkRect& visibleRect, float scale) {
+ m_drawCount++;
+ return false;
+ }
+
+ bool isReady() {
+ return m_isDonePainting;
+ }
+
+ LayerAndroid* copy() const { return new TestLayerAndroid(*this); }
+};
+
+class TreeManagerTest : public testing::Test {
+protected:
+ IntRect m_iRect;
+ SkRect m_sRect;
+ double m_scale;
+
+ void allocLayerWithPicture(bool useTestLayer, LayerAndroid** layerHandle, SkPicture** pictureHandle) {
+ SkPicture* p = new SkPicture();
+ p->beginRecording(16,16, 0);
+ p->endRecording();
+
+ LayerAndroid* l;
+ if (useTestLayer)
+ l = new TestLayerAndroid(p);
+ else
+ l = new LayerAndroid(p);
+ l->setSize(16, 16);
+ SkSafeUnref(p); // layer takes sole ownership of picture
+
+ if (layerHandle)
+ *layerHandle = l;
+ if (pictureHandle)
+ *pictureHandle = p;
+ }
+
+ bool drawGL(TreeManager& manager, bool* swappedPtr) {
+ // call draw gl here in one place, so that when its parameters change,
+ // the tests only have to be updated in one place
+ return manager.drawGL(0, m_iRect, m_sRect, m_scale, false, swappedPtr, 0);
+ }
+
+ virtual void SetUp() {
+ m_iRect = IntRect(0, 0, 1, 1);
+ m_sRect = SkRect::MakeWH(1, 1);
+ m_scale = 1.0;
+ }
+ virtual void TearDown() { }
+};
+
+TEST_F(TreeManagerTest, EmptyTree_DoesntRedraw) {
+ TreeManager manager;
+
+ drawGL(manager, false);
+}
+
+TEST_F(TreeManagerTest, OneLayerTree_SingleTree_SwapCheck) {
+ TreeManager manager;
+ TestLayer layer;
+
+ // initialize with tree, should be painting
+ manager.updateWithTree(&layer, true);
+
+ ASSERT_TRUE(layer.m_isPainting);
+ ASSERT_FALSE(layer.m_isDrawing);
+
+ // should not call swap, and return true since content isn't done
+ for (int i = 1; i < 6; i++) {
+ bool swapped = false;
+ ASSERT_TRUE(drawGL(manager, &swapped));
+ ASSERT_FALSE(swapped);
+ ASSERT_EQ(layer.m_drawCount, 0);
+ }
+
+ layer.m_isDonePainting = true;
+
+ // swap content, should return false since no new picture
+ bool swapped = false;
+ ASSERT_FALSE(drawGL(manager, &swapped));
+ ASSERT_TRUE(swapped);
+ ASSERT_EQ(layer.m_drawCount, 1); // verify layer drawn
+}
+
+TEST_F(TreeManagerTest, OneLayerTree_SingleTree_RefCountCorrectly) {
+ TreeManager manager;
+ TestLayer* layer = new TestLayer();
+ ASSERT_EQ(layer->getRefCnt(), 1);
+
+ // initialize with tree, should be painting
+ manager.updateWithTree(layer, true);
+ ASSERT_EQ(layer->getRefCnt(), 2);
+
+ layer->m_isDonePainting = true;
+ ASSERT_FALSE(drawGL(manager, 0));
+
+ // should be drawing
+ ASSERT_EQ(layer->getRefCnt(), 2);
+
+ manager.updateWithTree(0, false);
+
+ // layer should be removed
+ ASSERT_EQ(layer->getRefCnt(), 1);
+ SkSafeUnref(layer);
+}
+
+TEST_F(TreeManagerTest, OneLayerTree_TwoTreeFlush_PaintDrawRefCheck) {
+ TreeManager manager;
+ TestLayer* firstLayer = new TestLayer();
+ TestLayer* secondLayer = new TestLayer();
+ ASSERT_EQ(firstLayer->getRefCnt(), 1);
+ ASSERT_EQ(secondLayer->getRefCnt(), 1);
+
+ ///// ENQUEUE 2 TREES
+
+ // first starts painting
+ manager.updateWithTree(firstLayer, true);
+ ASSERT_TRUE(firstLayer->m_isPainting);
+ ASSERT_FALSE(firstLayer->m_isDrawing);
+
+ // second is queued
+ manager.updateWithTree(secondLayer, false);
+ ASSERT_FALSE(secondLayer->m_isPainting);
+ ASSERT_FALSE(secondLayer->m_isDrawing);
+
+ // nothing changes
+ ASSERT_TRUE(drawGL(manager, 0));
+
+ ////////// FIRST FINISHES PAINTING, SWAP THE TREES
+
+ firstLayer->m_isDonePainting = true;
+ bool swapped = false;
+ ASSERT_TRUE(drawGL(manager, &swapped));
+ ASSERT_TRUE(swapped);
+
+ // first is drawing
+ ASSERT_EQ(firstLayer->m_drawCount, 1);
+ ASSERT_FALSE(firstLayer->m_isPainting);
+ ASSERT_TRUE(firstLayer->m_isDrawing);
+ ASSERT_EQ(firstLayer->getRefCnt(), 2);
+
+ // second is painting (and hasn't drawn)
+ ASSERT_EQ(secondLayer->m_drawCount, 0);
+ ASSERT_TRUE(secondLayer->m_isPainting);
+ ASSERT_FALSE(secondLayer->m_isDrawing);
+ ASSERT_EQ(secondLayer->getRefCnt(), 2);
+
+ ////////// SECOND FINISHES PAINTING, SWAP AGAIN
+
+ secondLayer->m_isDonePainting = true;
+
+ // draw again, swap, first should be deleted
+ swapped = false;
+ ASSERT_FALSE(drawGL(manager, &swapped)); // no painting layer
+ ASSERT_TRUE(swapped);
+
+ // first layer gone!
+ ASSERT_EQ(firstLayer->getRefCnt(), 1);
+ SkSafeUnref(firstLayer);
+
+ // second is drawing
+ ASSERT_EQ(secondLayer->m_drawCount, 1);
+ ASSERT_FALSE(secondLayer->m_isPainting);
+ ASSERT_TRUE(secondLayer->m_isDrawing);
+ ASSERT_EQ(secondLayer->getRefCnt(), 2);
+
+ ////////// INSERT NULL, BOTH TREES NOW REMOVED
+
+ // insert null tree, which should deref secondLayer immediately
+ manager.updateWithTree(0, false);
+ ASSERT_EQ(secondLayer->getRefCnt(), 1);
+ SkSafeUnref(secondLayer);
+
+ // nothing to draw or swap
+ swapped = false;
+ ASSERT_FALSE(drawGL(manager, &swapped));
+ ASSERT_FALSE(swapped);
+}
+
+TEST_F(TreeManagerTest, LayerAndroidTree_PictureRefCount) {
+ RenderLayer* renderLayer = 0;
+ LayerAndroid* l;
+ SkPicture* p;
+ allocLayerWithPicture(false, &l, &p);
+ ASSERT_TRUE(l->needsTexture());
+ SkSafeRef(p); // ref picture locally so it exists after layer (so we can see
+ // layer derefs it)
+
+ ASSERT_EQ(l->getRefCnt(), 1);
+ ASSERT_EQ(p->getRefCnt(), 2);
+ SkSafeUnref(l);
+
+ ASSERT_EQ(p->getRefCnt(), 1);
+ SkSafeUnref(p);
+}
+
+TEST_F(TreeManagerTest, LayerAndroidTree_PaintTreeWithPictures) {
+ XLOGC("STARTING PAINT TEST");
+
+ TreeManager manager;
+ RenderLayer* renderLayer = 0;
+ LayerAndroid root(renderLayer);
+ LayerAndroid* noPaintChild = new LayerAndroid(renderLayer);
+ root.addChild(noPaintChild);
+
+ root.showLayer(0);
+
+ ASSERT_EQ(noPaintChild->getRefCnt(), 2);
+
+
+ LayerAndroid* copy = new LayerAndroid(root);
+ copy->showLayer(0);
+ manager.updateWithTree(copy, true);
+
+
+ // no painting layer, should swap immediately
+ bool swapped = false;
+ ASSERT_FALSE(drawGL(manager, &swapped));
+ ASSERT_TRUE(swapped);
+
+
+ ////////// add 2 painting layers, push new tree copy into tree manager
+
+ LayerAndroid* paintChildA;
+ allocLayerWithPicture(true, &paintChildA, 0);
+ noPaintChild->addChild(paintChildA);
+ ASSERT_TRUE(paintChildA->needsTexture());
+
+ LayerAndroid* paintChildB;
+ allocLayerWithPicture(true, &paintChildB, 0);
+ noPaintChild->addChild(paintChildB);
+ ASSERT_TRUE(paintChildB->needsTexture());
+
+ LayerAndroid* copy1 = new LayerAndroid(root);
+ copy1->showLayer(0);
+ manager.updateWithTree(copy1, false);
+
+ swapped = false;
+ ASSERT_TRUE(drawGL(manager, &swapped));
+ ASSERT_FALSE(swapped); // painting layers not ready
+
+ ASSERT_EQ(TreeManager::getTotalPaintedSurfaceCount(), 2);
+
+ ////////// remove painting layer, add new painting layer, push new tree copy into tree manager
+
+ LayerAndroid* paintChildC;
+ allocLayerWithPicture(true, &paintChildC, 0);
+ noPaintChild->addChild(paintChildC);
+ ASSERT_TRUE(paintChildC->needsTexture());
+
+ paintChildB->detachFromParent();
+ ASSERT_EQ(paintChildB->getRefCnt(), 1);
+ SkSafeUnref(paintChildB);
+
+ LayerAndroid* copy2 = new LayerAndroid(root);
+ copy2->showLayer(0);
+ manager.updateWithTree(copy2, false);
+
+ swapped = false;
+ ASSERT_TRUE(drawGL(manager, &swapped));
+ ASSERT_FALSE(swapped); // painting layers not ready
+
+
+ ////////// swap layers
+
+ static_cast<TestLayerAndroid*>(copy1->getChild(0)->getChild(0))->m_isDonePainting = true;
+ static_cast<TestLayerAndroid*>(copy1->getChild(0)->getChild(1))->m_isDonePainting = true;
+
+ XLOGC("painting should be %p, queued %p", copy1, copy2);
+ swapped = false;
+ ASSERT_TRUE(drawGL(manager, &swapped));
+ ASSERT_TRUE(swapped); // paint complete, new layer tree to paint
+ XLOGC("drawing should be %p, painting %p", copy1, copy2);
+
+
+ ASSERT_EQ(TreeManager::getTotalPaintedSurfaceCount(), 3);
+
+
+ ////////// swap layers again
+
+ static_cast<TestLayerAndroid*>(copy2->getChild(0)->getChild(0))->m_isDonePainting = true;
+ static_cast<TestLayerAndroid*>(copy2->getChild(0)->getChild(1))->m_isDonePainting = true;
+
+ swapped = false;
+ ASSERT_FALSE(drawGL(manager, &swapped));
+ ASSERT_TRUE(swapped); // paint complete, no new layer tree to paint
+
+ ASSERT_EQ(TreeManager::getTotalPaintedSurfaceCount(), 2);
+
+ ////////// remove all painting layers
+
+ paintChildA->detachFromParent();
+ SkSafeUnref(paintChildA);
+ paintChildC->detachFromParent();
+ SkSafeUnref(paintChildC);
+
+
+ copy = new LayerAndroid(root);
+ copy->showLayer(0);
+ manager.updateWithTree(copy, false);
+
+ swapped = false;
+ ASSERT_FALSE(drawGL(manager, &swapped));
+ ASSERT_TRUE(swapped); // paint complete, no new layer tree to paint
+
+ ASSERT_EQ(TreeManager::getTotalPaintedSurfaceCount(), 0);
+}
+
+} // namespace WebCore
diff --git a/Source/WebKit/android/WebCoreSupport/CacheResult.cpp b/Source/WebKit/android/WebCoreSupport/CacheResult.cpp
index 5309c66..6710e49 100644
--- a/Source/WebKit/android/WebCoreSupport/CacheResult.cpp
+++ b/Source/WebKit/android/WebCoreSupport/CacheResult.cpp
@@ -134,11 +134,11 @@ bool CacheResult::writeToFile(const String& filePath) const
if (!thread)
return false;
- CacheResult* me = const_cast<CacheResult*>(this);
- thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(me, &CacheResult::writeToFileImpl));
-
m_filePath = filePath.threadsafeCopy();
m_isAsyncOperationInProgress = true;
+
+ thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(const_cast<CacheResult*>(this), &CacheResult::writeToFileImpl));
+
while (m_isAsyncOperationInProgress)
m_condition.wait(m_mutex);
@@ -213,10 +213,9 @@ HttpResponseHeaders* CacheResult::responseHeaders() const
if (!thread)
return 0;
- CacheResult* me = const_cast<CacheResult*>(this);
- thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(me, &CacheResult::responseHeadersImpl));
-
m_isAsyncOperationInProgress = true;
+ thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(const_cast<CacheResult*>(this), &CacheResult::responseHeadersImpl));
+
while (m_isAsyncOperationInProgress)
m_condition.wait(m_mutex);
diff --git a/Source/WebKit/android/jni/CacheManager.cpp b/Source/WebKit/android/jni/CacheManager.cpp
index 144b62a..f600d00 100644
--- a/Source/WebKit/android/jni/CacheManager.cpp
+++ b/Source/WebKit/android/jni/CacheManager.cpp
@@ -90,6 +90,7 @@ static jobject getCacheResult(JNIEnv* env, jobject, jstring url)
String urlWtfString = jstringToWtfString(env, url);
Vector<char> encodedUrl;
base64Encode(urlWtfString.utf8().data(), urlWtfString.length(), encodedUrl, false /*insertLFs*/);
+ encodedUrl.append('\0');
String filePath = pathByAppendingComponent(getCacheFileBaseDir(env), encodedUrl.data());
if (!result->writeToFile(filePath))
return 0;
diff --git a/Source/WebKit/android/jni/ViewStateSerializer.cpp b/Source/WebKit/android/jni/ViewStateSerializer.cpp
index 93f4375..6b473f5 100644
--- a/Source/WebKit/android/jni/ViewStateSerializer.cpp
+++ b/Source/WebKit/android/jni/ViewStateSerializer.cpp
@@ -111,11 +111,6 @@ static BaseLayerAndroid* nativeDeserializeViewState(JNIEnv* env, jobject, jobjec
if (childLayer)
layer->addChild(childLayer);
}
- // Now double back and delete any imageRefs
- for (int i = 0; i < layer->countChildren(); i++) {
- LayerAndroid* childLayer = static_cast<LayerAndroid*>(layer->getChild(i));
- cleanupImageRefs(childLayer);
- }
delete stream;
return layer;
}
@@ -297,15 +292,16 @@ void serializeLayer(LayerAndroid* layer, SkWStream* stream)
stream->writeBool(layer->m_preserves3D);
stream->writeScalar(layer->m_anchorPointZ);
stream->writeScalar(layer->m_drawOpacity);
- bool hasContentsImage = layer->m_imageRef != 0;
+ bool hasContentsImage = layer->m_imageCRC != 0;
stream->writeBool(hasContentsImage);
if (hasContentsImage) {
SkFlattenableWriteBuffer buffer(1024);
buffer.setFlags(SkFlattenableWriteBuffer::kCrossProcess_Flag);
ImageTexture* imagetexture =
- ImagesManager::instance()->getTextureForImage(layer->m_imageRef, false);
+ ImagesManager::instance()->retainImage(layer->m_imageCRC);
if (imagetexture && imagetexture->bitmap())
imagetexture->bitmap()->flatten(buffer);
+ ImagesManager::instance()->releaseImage(layer->m_imageCRC);
stream->write32(buffer.size());
buffer.writeToStream(stream);
}
@@ -388,8 +384,7 @@ LayerAndroid* deserializeLayer(SkStream* stream)
contentsImage.unflatten(buffer);
SkBitmapRef* imageRef = new SkBitmapRef(contentsImage);
layer->setContentsImage(imageRef);
- // We delay deleting the imageRef until after deserialization to make
- // sure we have unique keys
+ delete imageRef;
}
bool hasRecordingPicture = stream->readBool();
if (hasRecordingPicture) {
@@ -418,17 +413,6 @@ LayerAndroid* deserializeLayer(SkStream* stream)
return layer;
}
-void cleanupImageRefs(LayerAndroid* layer)
-{
- if (!layer)
- return;
- int count = layer->countChildren();
- for (int i = 0; i < count; i++)
- cleanupImageRefs(layer->getChild(i));
- if (layer->m_imageRef)
- delete layer->m_imageRef;
-}
-
/*
* JNI registration
*/
diff --git a/Source/WebKit/android/jni/WebHistory.cpp b/Source/WebKit/android/jni/WebHistory.cpp
index 7ec73a3..aa74b81 100644
--- a/Source/WebKit/android/jni/WebHistory.cpp
+++ b/Source/WebKit/android/jni/WebHistory.cpp
@@ -490,7 +490,7 @@ static bool read_item_recursive(WebCore::HistoryItem* newItem,
// Read the original url
// Read the expected length of the string.
- int l;
+ unsigned l;
memcpy(&l, data, sizeofUnsigned);
// Increment data pointer by the size of an unsigned int.
data += sizeofUnsigned;
diff --git a/Source/WebKit/android/jni/WebViewCore.cpp b/Source/WebKit/android/jni/WebViewCore.cpp
index 7692de1..839c352 100644
--- a/Source/WebKit/android/jni/WebViewCore.cpp
+++ b/Source/WebKit/android/jni/WebViewCore.cpp
@@ -885,29 +885,37 @@ bool WebViewCore::updateLayers(LayerAndroid* layers)
ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client());
GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync());
if (root) {
- root->notifyClientAnimationStarted();
LayerAndroid* updatedLayer = root->contentLayer();
return layers->updateWithTree(updatedLayer);
}
return true;
}
+void WebViewCore::notifyAnimationStarted()
+{
+ // We notify webkit that the animations have begun
+ // TODO: handle case where not all have begun
+ ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client());
+ GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync());
+ if (root)
+ root->notifyClientAnimationStarted();
+
+}
+
BaseLayerAndroid* WebViewCore::createBaseLayer(SkRegion* region)
{
BaseLayerAndroid* base = new BaseLayerAndroid();
base->setContent(m_content);
- if (!region->isEmpty()) {
- m_skipContentDraw = true;
- bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame);
- m_skipContentDraw = false;
- // Layout only fails if called during a layout.
- LOG_ASSERT(layoutSucceeded, "Can never be called recursively");
- }
+ m_skipContentDraw = true;
+ bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame);
+ m_skipContentDraw = false;
+ // Layout only fails if called during a layout.
+ LOG_ASSERT(layoutSucceeded, "Can never be called recursively");
#if USE(ACCELERATED_COMPOSITING)
// We set the background color
- if (!region->isEmpty() && m_mainFrame && m_mainFrame->document()
+ if (m_mainFrame && m_mainFrame->document()
&& m_mainFrame->document()->body()) {
Document* document = m_mainFrame->document();
RefPtr<RenderStyle> style = document->styleForElementIgnoringPendingStylesheets(document->body());
@@ -922,7 +930,6 @@ BaseLayerAndroid* WebViewCore::createBaseLayer(SkRegion* region)
ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client());
GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync());
if (root) {
- root->notifyClientAnimationStarted();
LayerAndroid* copyLayer = new LayerAndroid(*root->contentLayer());
base->addChild(copyLayer);
copyLayer->unref();
@@ -4106,9 +4113,9 @@ void WebViewCore::addVisitedLink(const UChar* string, int length)
m_groupForVisitedLinks->addVisitedLink(string, length);
}
-static bool UpdateLayers(JNIEnv *env, jobject obj, jint jbaseLayer)
+static bool UpdateLayers(JNIEnv *env, jobject obj, jint nativeClass, jint jbaseLayer)
{
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ WebViewCore* viewImpl = (WebViewCore*) nativeClass;
BaseLayerAndroid* baseLayer = (BaseLayerAndroid*) jbaseLayer;
if (baseLayer) {
LayerAndroid* root = static_cast<LayerAndroid*>(baseLayer->getChild(0));
@@ -4118,6 +4125,12 @@ static bool UpdateLayers(JNIEnv *env, jobject obj, jint jbaseLayer)
return true;
}
+static void NotifyAnimationStarted(JNIEnv *env, jobject obj, jint nativeClass)
+{
+ WebViewCore* viewImpl = (WebViewCore*) nativeClass;
+ viewImpl->notifyAnimationStarted();
+}
+
static jint RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt)
{
#ifdef ANDROID_INSTRUMENT
@@ -4697,8 +4710,10 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = {
(void*) UpdateFrameCache },
{ "nativeGetContentMinPrefWidth", "()I",
(void*) GetContentMinPrefWidth },
- { "nativeUpdateLayers", "(I)Z",
+ { "nativeUpdateLayers", "(II)Z",
(void*) UpdateLayers },
+ { "nativeNotifyAnimationStarted", "(I)V",
+ (void*) NotifyAnimationStarted },
{ "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)I",
(void*) RecordContent },
{ "setViewportSettingsFromNative", "()V",
diff --git a/Source/WebKit/android/jni/WebViewCore.h b/Source/WebKit/android/jni/WebViewCore.h
index acde590..a05c3ea 100644
--- a/Source/WebKit/android/jni/WebViewCore.h
+++ b/Source/WebKit/android/jni/WebViewCore.h
@@ -529,6 +529,7 @@ namespace android {
// as we are calling layersSync().
BaseLayerAndroid* createBaseLayer(SkRegion*);
bool updateLayers(LayerAndroid*);
+ void notifyAnimationStarted();
int textWrapWidth() const { return m_textWrapWidth; }
float scale() const { return m_scale; }
diff --git a/Source/WebKit/android/nav/CacheBuilder.cpp b/Source/WebKit/android/nav/CacheBuilder.cpp
index 0c9e85c..940991f 100644
--- a/Source/WebKit/android/nav/CacheBuilder.cpp
+++ b/Source/WebKit/android/nav/CacheBuilder.cpp
@@ -1161,8 +1161,6 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
absBounds.move(globalOffsetX, globalOffsetY);
hasClip = nodeRenderer->hasOverflowClip();
- if (node->hasTagName(HTMLNames::canvasTag))
- mPictureSetDisabled = true;
if (checkForPluginViewThatWantsFocus(nodeRenderer)) {
bounds = absBounds;
isUnclipped = true;
@@ -1269,6 +1267,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
type = TEXT_INPUT_CACHEDNODETYPE;
cachedInput.setFormPointer(area->form());
cachedInput.setIsTextArea(true);
+ cachedInput.setSpellcheck(area->spellcheck());
exported = area->value().threadsafeCopy();
} else if (node->hasTagName(HTMLNames::aTag)) {
const HTMLAnchorElement* anchorNode =
diff --git a/Source/WebKit/android/nav/WebView.cpp b/Source/WebKit/android/nav/WebView.cpp
index aea28bd..76f0fb8 100644
--- a/Source/WebKit/android/nav/WebView.cpp
+++ b/Source/WebKit/android/nav/WebView.cpp
@@ -119,7 +119,6 @@ enum DrawExtras { // keep this in sync with WebView.java
struct JavaGlue {
jweak m_obj;
- jmethodID m_calcOurContentVisibleRectF;
jmethodID m_overrideLoading;
jmethodID m_scrollBy;
jmethodID m_sendMoveFocus;
@@ -150,14 +149,15 @@ struct JavaGlue {
}
} m_javaGlue;
-WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir) :
+WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir,
+ bool isHighEndGfx) :
m_ring((WebViewCore*) viewImpl)
+ , m_isHighEndGfx(isHighEndGfx)
{
jclass clazz = env->FindClass("android/webkit/WebView");
// m_javaGlue = new JavaGlue;
m_javaGlue.m_obj = env->NewWeakGlobalRef(javaWebView);
m_javaGlue.m_scrollBy = GetJMethod(env, clazz, "setContentScrollBy", "(IIZ)Z");
- m_javaGlue.m_calcOurContentVisibleRectF = GetJMethod(env, clazz, "calcOurContentVisibleRectF", "(Landroid/graphics/RectF;)V");
m_javaGlue.m_overrideLoading = GetJMethod(env, clazz, "overrideLoading", "(Ljava/lang/String;)V");
m_javaGlue.m_sendMoveFocus = GetJMethod(env, clazz, "sendMoveFocus", "(II)V");
m_javaGlue.m_sendMoveMouse = GetJMethod(env, clazz, "sendMoveMouse", "(IIII)V");
@@ -172,7 +172,7 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir)
m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V");
m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz,
"viewInvalidateDelayed", "(JIIII)V");
- m_javaGlue.m_pageSwapCallback = GetJMethod(env, clazz, "pageSwapCallback", "()V");
+ m_javaGlue.m_pageSwapCallback = GetJMethod(env, clazz, "pageSwapCallback", "(Z)V");
m_javaGlue.m_inFullScreenMode = GetJMethod(env, clazz, "inFullScreenMode", "()Z");
m_javaGlue.m_getTextHandleScale = GetJMethod(env, clazz, "getTextHandleScale", "()F");
env->DeleteLocalRef(clazz);
@@ -369,50 +369,29 @@ void scrollRectOnScreen(const IntRect& rect)
{
if (rect.isEmpty())
return;
- SkRect visible = SkRect::MakeEmpty();
- calcOurContentVisibleRect(&visible);
int dx = 0;
int left = rect.x();
int right = rect.maxX();
- if (left < visible.fLeft) {
- dx = left - visible.fLeft;
+ if (left < m_visibleRect.fLeft)
+ dx = left - m_visibleRect.fLeft;
// Only scroll right if the entire width can fit on screen.
- } else if (right > visible.fRight && right - left < visible.width()) {
- dx = right - visible.fRight;
- }
+ else if (right > m_visibleRect.fRight
+ && right - left < m_visibleRect.width())
+ dx = right - m_visibleRect.fRight;
int dy = 0;
int top = rect.y();
int bottom = rect.maxY();
- if (top < visible.fTop) {
- dy = top - visible.fTop;
+ if (top < m_visibleRect.fTop)
+ dy = top - m_visibleRect.fTop;
// Only scroll down if the entire height can fit on screen
- } else if (bottom > visible.fBottom && bottom - top < visible.height()) {
- dy = bottom - visible.fBottom;
- }
+ else if (bottom > m_visibleRect.fBottom
+ && bottom - top < m_visibleRect.height())
+ dy = bottom - m_visibleRect.fBottom;
if ((dx|dy) == 0 || !scrollBy(dx, dy))
return;
viewInvalidate();
}
-void calcOurContentVisibleRect(SkRect* r)
-{
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- AutoJObject javaObject = m_javaGlue.object(env);
- if (!javaObject.get())
- return;
- jclass rectClass = env->FindClass("android/graphics/RectF");
- jmethodID init = env->GetMethodID(rectClass, "<init>", "(FFFF)V");
- jobject jRect = env->NewObject(rectClass, init, 0, 0, 0, 0);
- env->CallVoidMethod(javaObject.get(), m_javaGlue.m_calcOurContentVisibleRectF, jRect);
- r->fLeft = env->GetFloatField(jRect, m_javaGlue.m_rectFLeft);
- r->fTop = env->GetFloatField(jRect, m_javaGlue.m_rectFTop);
- r->fRight = r->fLeft + env->CallFloatMethod(jRect, m_javaGlue.m_rectFWidth);
- r->fBottom = r->fTop + env->CallFloatMethod(jRect, m_javaGlue.m_rectFHeight);
- env->DeleteLocalRef(rectClass);
- env->DeleteLocalRef(jRect);
- checkException(env);
-}
-
void resetCursorRing()
{
m_ringAnimationEnd = 0;
@@ -438,9 +417,7 @@ bool drawCursorPreamble(CachedRoot* root)
#if USE(ACCELERATED_COMPOSITING)
if (node->isInLayer() && root->rootLayer()) {
LayerAndroid* layer = root->rootLayer();
- SkRect visible;
- calcOurContentVisibleRect(&visible);
- layer->updateFixedLayersPositions(visible);
+ layer->updateFixedLayersPositions(m_visibleRect);
layer->updatePositions();
}
#endif
@@ -469,8 +446,9 @@ void drawCursorPostamble()
}
}
-bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect, WebCore::IntRect& webViewRect,
- int titleBarHeight, WebCore::IntRect& clip, float scale, int extras)
+bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect,
+ WebCore::IntRect& webViewRect, int titleBarHeight,
+ WebCore::IntRect& clip, float scale, int extras)
{
#if USE(ACCELERATED_COMPOSITING)
if (!m_baseLayer || inFullScreenMode())
@@ -478,6 +456,7 @@ bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect, WebCore::In
if (!m_glWebViewState) {
m_glWebViewState = new GLWebViewState();
+ m_glWebViewState->setHighEndGfx(m_isHighEndGfx);
m_glWebViewState->glExtras()->setCursorRingExtra(&m_ring);
m_glWebViewState->glExtras()->setFindOnPageExtra(&m_findOnPage);
if (m_baseLayer->content()) {
@@ -521,24 +500,23 @@ bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect, WebCore::In
unsigned int pic = m_glWebViewState->currentPictureCounter();
m_glWebViewState->glExtras()->setDrawExtra(extra);
- SkRect visibleRect;
- calcOurContentVisibleRect(&visibleRect);
// Make sure we have valid coordinates. We might not have valid coords
// if the zoom manager is still initializing. We will be redrawn
// once the correct scale is set
- if (!visibleRect.hasValidCoordinates())
+ if (!m_visibleRect.hasValidCoordinates())
return false;
- bool pagesSwapped = false;
- bool ret = m_glWebViewState->drawGL(viewRect, visibleRect, invalRect,
+ bool treesSwapped = false;
+ bool newTreeHasAnim = false;
+ bool ret = m_glWebViewState->drawGL(viewRect, m_visibleRect, invalRect,
webViewRect, titleBarHeight, clip, scale,
- &pagesSwapped);
- if (m_pageSwapCallbackRegistered && pagesSwapped) {
+ &treesSwapped, &newTreeHasAnim);
+ if (treesSwapped && (m_pageSwapCallbackRegistered || newTreeHasAnim)) {
m_pageSwapCallbackRegistered = false;
LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject javaObject = m_javaGlue.object(env);
if (javaObject.get()) {
- env->CallVoidMethod(javaObject.get(), m_javaGlue.m_pageSwapCallback);
+ env->CallVoidMethod(javaObject.get(), m_javaGlue.m_pageSwapCallback, newTreeHasAnim);
checkException(env);
}
}
@@ -597,11 +575,9 @@ PictureSet* draw(SkCanvas* canvas, SkColor bgColor, int extras, bool split)
#if USE(ACCELERATED_COMPOSITING)
LayerAndroid* compositeLayer = compositeRoot();
if (compositeLayer) {
- SkRect visible;
- calcOurContentVisibleRect(&visible);
// call this to be sure we've adjusted for any scrolling or animations
// before we actually draw
- compositeLayer->updateFixedLayersPositions(visible);
+ compositeLayer->updateFixedLayersPositions(m_visibleRect);
compositeLayer->updatePositions();
// We have to set the canvas' matrix on the base layer
// (to have fixed layers work as intended)
@@ -743,12 +719,10 @@ CachedRoot* getFrameCache(FrameCachePermission allowNewer)
m_frameCacheUI->setRootLayer(compositeRoot());
#if USE(ACCELERATED_COMPOSITING)
if (layerId >= 0) {
- SkRect visible;
- calcOurContentVisibleRect(&visible);
LayerAndroid* layer = const_cast<LayerAndroid*>(
m_frameCacheUI->rootLayer());
if (layer) {
- layer->updateFixedLayersPositions(visible);
+ layer->updateFixedLayersPositions(m_visibleRect);
layer->updatePositions();
}
}
@@ -1119,6 +1093,12 @@ int scrollableLayer(int x, int y, SkIRect* layerRect, SkIRect* bounds)
return 0;
}
+void scrollLayer(int layerId, int x, int y)
+{
+ if (m_glWebViewState)
+ m_glWebViewState->scrollLayer(layerId, x, y);
+}
+
int getBlockLeftEdge(int x, int y, float scale)
{
CachedRoot* root = getFrameCache(AllowNewer);
@@ -1485,6 +1465,7 @@ void setBaseLayer(BaseLayerAndroid* layer, SkRegion& inval, bool showVisualIndic
#if ENABLE(ANDROID_OVERFLOW_SCROLL)
if (layer) {
+ // TODO: the below tree copies are only necessary in software rendering
LayerAndroid* newCompositeRoot = static_cast<LayerAndroid*>(layer->getChild(0));
copyScrollPositionRecursive(compositeRoot(), newCompositeRoot);
}
@@ -1545,6 +1526,10 @@ BaseLayerAndroid* getBaseLayer() {
return m_baseLayer;
}
+void setVisibleRect(SkRect& visibleRect) {
+ m_visibleRect = visibleRect;
+}
+
bool m_isDrawingPaused;
private: // local state for WebView
// private to getFrameCache(); other functions operate in a different thread
@@ -1567,6 +1552,8 @@ private: // local state for WebView
bool m_pageSwapCallbackRegistered;
#endif
RenderSkinButton* m_buttonSkin;
+ SkRect m_visibleRect;
+ bool m_isHighEndGfx;
}; // end of WebView class
@@ -1578,7 +1565,9 @@ private: // local state for WebView
class GLDrawFunctor : Functor {
public:
GLDrawFunctor(WebView* _wvInstance,
- bool(WebView::*_funcPtr)(WebCore::IntRect&, WebCore::IntRect*, WebCore::IntRect&, int, WebCore::IntRect&, jfloat, jint),
+ bool(WebView::*_funcPtr)(WebCore::IntRect&, WebCore::IntRect*,
+ WebCore::IntRect&, int, WebCore::IntRect&,
+ jfloat, jint),
WebCore::IntRect _viewRect, float _scale, int _extras) {
wvInstance = _wvInstance;
funcPtr = _funcPtr;
@@ -1603,8 +1592,10 @@ class GLDrawFunctor : Functor {
WebCore::IntRect clip(info->clipLeft, info->clipTop,
info->clipRight - info->clipLeft,
info->clipBottom - info->clipTop);
+ TilesManager::instance()->shader()->setWebViewMatrix(info->transform, info->isLayer);
- bool retVal = (*wvInstance.*funcPtr)(localViewRect, &inval, webViewRect, titlebarHeight, clip, scale, extras);
+ bool retVal = (*wvInstance.*funcPtr)(localViewRect, &inval, webViewRect,
+ titlebarHeight, clip, scale, extras);
if (retVal) {
IntRect finalInval;
if (inval.isEmpty()) {
@@ -1632,7 +1623,8 @@ class GLDrawFunctor : Functor {
}
private:
WebView* wvInstance;
- bool (WebView::*funcPtr)(WebCore::IntRect&, WebCore::IntRect*, WebCore::IntRect&, int, WebCore::IntRect&, float, int);
+ bool (WebView::*funcPtr)(WebCore::IntRect&, WebCore::IntRect*,
+ WebCore::IntRect&, int, WebCore::IntRect&, float, int);
WebCore::IntRect viewRect;
WebCore::IntRect webViewRect;
jfloat scale;
@@ -1683,10 +1675,11 @@ static void nativeClearCursor(JNIEnv *env, jobject obj)
view->clearCursor();
}
-static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl, jstring drawableDir)
+static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl,
+ jstring drawableDir, jboolean isHighEndGfx)
{
WTF::String dir = jstringToWtfString(env, drawableDir);
- WebView* webview = new WebView(env, obj, viewImpl, dir);
+ WebView* webview = new WebView(env, obj, viewImpl, dir, isHighEndGfx);
// NEED THIS OR SOMETHING LIKE IT!
//Release(obj);
}
@@ -1816,9 +1809,20 @@ static jobject nativeCursorPosition(JNIEnv *env, jobject obj)
static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
{
- int L, T, R, B;
- GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
- return WebCore::IntRect(L, T, R - L, B - T);
+ if (obj) {
+ int L, T, R, B;
+ GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
+ return WebCore::IntRect(L, T, R - L, B - T);
+ } else
+ return WebCore::IntRect();
+}
+
+static SkRect jrectf_to_rect(JNIEnv* env, jobject obj)
+{
+ SkRect rect = SkRect::MakeEmpty();
+ if (obj)
+ GraphicsJNI::jrectf_to_rect(env, obj, &rect);
+ return rect;
}
static bool nativeCursorIntersects(JNIEnv *env, jobject obj, jobject visRect)
@@ -1859,56 +1863,49 @@ static void nativeDebugDump(JNIEnv *env, jobject obj)
#endif
}
-static jint nativeDraw(JNIEnv *env, jobject obj, jobject canv, jint color,
+static jint nativeDraw(JNIEnv *env, jobject obj, jobject canv,
+ jobject visible, jint color,
jint extras, jboolean split) {
SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
- return reinterpret_cast<jint>(GET_NATIVE_VIEW(env, obj)->draw(canvas, color, extras, split));
+ WebView* webView = GET_NATIVE_VIEW(env, obj);
+ SkRect visibleRect = jrectf_to_rect(env, visible);
+ webView->setVisibleRect(visibleRect);
+ PictureSet* pictureSet = webView->draw(canvas, color, extras, split);
+ return reinterpret_cast<jint>(pictureSet);
}
static jint nativeGetDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView,
jobject jrect, jobject jviewrect,
+ jobject jvisiblerect,
jfloat scale, jint extras) {
- WebCore::IntRect viewRect;
- if (jrect == NULL) {
- viewRect = WebCore::IntRect();
- } else {
- viewRect = jrect_to_webrect(env, jrect);
- }
+ WebCore::IntRect viewRect = jrect_to_webrect(env, jrect);
WebView *wvInstance = (WebView*) nativeView;
- GLDrawFunctor* functor = new GLDrawFunctor(wvInstance, &android::WebView::drawGL,
- viewRect, scale, extras);
+ SkRect visibleRect = jrectf_to_rect(env, jvisiblerect);
+ wvInstance->setVisibleRect(visibleRect);
+
+ GLDrawFunctor* functor = new GLDrawFunctor(wvInstance,
+ &android::WebView::drawGL, viewRect, scale, extras);
wvInstance->setFunctor((Functor*) functor);
- WebCore::IntRect webViewRect;
- if (jviewrect == NULL) {
- webViewRect = WebCore::IntRect();
- } else {
- webViewRect = jrect_to_webrect(env, jviewrect);
- }
+ WebCore::IntRect webViewRect = jrect_to_webrect(env, jviewrect);
functor->updateViewRect(webViewRect);
return (jint)functor;
}
-static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jobject jrect, jobject jviewrect) {
+static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jobject jrect,
+ jobject jviewrect, jobject jvisiblerect) {
WebView *wvInstance = GET_NATIVE_VIEW(env, obj);
- if (wvInstance != NULL) {
+ if (wvInstance) {
GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor();
- if (functor != NULL) {
- WebCore::IntRect viewRect;
- if (jrect == NULL) {
- viewRect = WebCore::IntRect();
- } else {
- viewRect = jrect_to_webrect(env, jrect);
- }
+ if (functor) {
+ WebCore::IntRect viewRect = jrect_to_webrect(env, jrect);
functor->updateRect(viewRect);
- WebCore::IntRect webViewRect;
- if (jviewrect == NULL) {
- webViewRect = WebCore::IntRect();
- } else {
- webViewRect = jrect_to_webrect(env, jviewrect);
- }
+ SkRect visibleRect = jrectf_to_rect(env, jvisiblerect);
+ wvInstance->setVisibleRect(visibleRect);
+
+ WebCore::IntRect webViewRect = jrect_to_webrect(env, jviewrect);
functor->updateViewRect(webViewRect);
}
}
@@ -1916,10 +1913,13 @@ static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jobject jrect,
static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj, jint nativeView)
{
+ // only call in software rendering, initialize and evaluate animations
#if USE(ACCELERATED_COMPOSITING)
LayerAndroid* root = ((WebView*)nativeView)->compositeRoot();
- if (root)
+ if (root) {
+ root->initAnimations();
return root->evaluateAnimations();
+ }
#endif
return false;
}
@@ -2042,7 +2042,7 @@ static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj)
{
const CachedFrame* frame;
const CachedNode* node = getFocusCandidate(env, obj, &frame);
- WebCore::IntRect bounds = node ? node->bounds(frame)
+ WebCore::IntRect bounds = node ? node->originalAbsoluteBounds()
: WebCore::IntRect(0, 0, 0, 0);
// Inset the rect by 1 unit, so that the focus candidate's border can still
// be seen behind it.
@@ -2106,6 +2106,18 @@ static int nativeFocusCandidateType(JNIEnv *env, jobject obj)
return input->getType();
}
+static int nativeFocusCandidateLayerId(JNIEnv *env, jobject obj)
+{
+ const CachedFrame* frame = 0;
+ const CachedNode* node = getFocusNode(env, obj, &frame);
+ if (!node || !frame)
+ return -1;
+ const CachedLayer* layer = frame->layer(node);
+ if (!layer)
+ return -1;
+ return layer->uniqueId();
+}
+
static bool nativeFocusIsPlugin(JNIEnv *env, jobject obj)
{
const CachedNode* node = getFocusNode(env, obj);
@@ -2669,6 +2681,9 @@ static bool nativeScrollLayer(JNIEnv* env, jobject obj, jint layerId, jint x,
{
#if ENABLE(ANDROID_OVERFLOW_SCROLL)
WebView* view = GET_NATIVE_VIEW(env, obj);
+ view->scrollLayer(layerId, x, y);
+
+ //TODO: the below only needed for the SW rendering path
LayerAndroid* root = view->compositeRoot();
if (!root)
return false;
@@ -2725,7 +2740,7 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeCacheHitNodePointer },
{ "nativeClearCursor", "()V",
(void*) nativeClearCursor },
- { "nativeCreate", "(ILjava/lang/String;)V",
+ { "nativeCreate", "(ILjava/lang/String;Z)V",
(void*) nativeCreate },
{ "nativeCursorFramePointer", "()I",
(void*) nativeCursorFramePointer },
@@ -2751,11 +2766,11 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeDebugDump },
{ "nativeDestroy", "()V",
(void*) nativeDestroy },
- { "nativeDraw", "(Landroid/graphics/Canvas;IIZ)I",
+ { "nativeDraw", "(Landroid/graphics/Canvas;Landroid/graphics/RectF;IIZ)I",
(void*) nativeDraw },
- { "nativeGetDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;FI)I",
+ { "nativeGetDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;FI)I",
(void*) nativeGetDrawGLFunction },
- { "nativeUpdateDrawGLFunction", "(Landroid/graphics/Rect;Landroid/graphics/Rect;)V",
+ { "nativeUpdateDrawGLFunction", "(Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;)V",
(void*) nativeUpdateDrawGLFunction },
{ "nativeDumpDisplayTree", "(Ljava/lang/String;)V",
(void*) nativeDumpDisplayTree },
@@ -2801,6 +2816,8 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeFocusCandidateTextSize },
{ "nativeFocusCandidateType", "()I",
(void*) nativeFocusCandidateType },
+ { "nativeFocusCandidateLayerId", "()I",
+ (void*) nativeFocusCandidateLayerId },
{ "nativeFocusIsPlugin", "()Z",
(void*) nativeFocusIsPlugin },
{ "nativeFocusNodeBounds", "()Landroid/graphics/Rect;",