summaryrefslogtreecommitdiffstats
path: root/Source/WebKit/android
diff options
context:
space:
mode:
authorJohn Reck <jreck@google.com>2012-04-27 08:13:38 -0700
committerJohn Reck <jreck@google.com>2012-05-02 16:13:16 -0700
commite859a34171f2a36877d95197d118d962078f8aa0 (patch)
tree3c8b592536fa193bcb468c03e5f318c7d0edcf8e /Source/WebKit/android
parent8a3e157baecb453158df1f7bc81bfb4704448b2e (diff)
downloadexternal_webkit-e859a34171f2a36877d95197d118d962078f8aa0.zip
external_webkit-e859a34171f2a36877d95197d118d962078f8aa0.tar.gz
external_webkit-e859a34171f2a36877d95197d118d962078f8aa0.tar.bz2
Rewrite PictureSet with TURBO!
This changes how partial invals are done by adding a hybrid mode. What we used to do is generate a SkPicture for the new area. This SkPicture would possibly be larger than the actual inval, depending on various merge rules (more SkPictures == slower to draw a tile) The new code rewrites PictureSet entirely, preserving many of the old rules but cleans up the code and adds the concept of a "PrerenderedInval". This is a partial inval that WebKit has rasterized. By having WebKit produce both a SkPicture and a SkBitmap, we avoid needing to play back the picture and avoid overdrawing. We take this SkBitmap, and simply update the front textures with it. This gives us full partial invals through the entire system without hitting any driver bugs, and with minimal copies. And while the SkPicture may be larger than the inval, the SkBitmap that is rasterized is not - it matches the area webkit has said is dirty. Change-Id: Ieb7ecc9db0d4f679102fda004a43399f9b319ebc
Diffstat (limited to 'Source/WebKit/android')
-rw-r--r--Source/WebKit/android/AndroidLog.h7
-rw-r--r--Source/WebKit/android/jni/PicturePile.cpp309
-rw-r--r--Source/WebKit/android/jni/PicturePile.h121
-rw-r--r--Source/WebKit/android/jni/PictureSet.cpp1244
-rw-r--r--Source/WebKit/android/jni/PictureSet.h152
-rw-r--r--Source/WebKit/android/jni/ViewStateSerializer.cpp1
-rw-r--r--Source/WebKit/android/jni/WebCoreViewBridge.h2
-rw-r--r--Source/WebKit/android/jni/WebViewCore.cpp248
-rw-r--r--Source/WebKit/android/jni/WebViewCore.h18
-rw-r--r--Source/WebKit/android/nav/WebView.cpp35
10 files changed, 509 insertions, 1628 deletions
diff --git a/Source/WebKit/android/AndroidLog.h b/Source/WebKit/android/AndroidLog.h
index e483169..f034d35 100644
--- a/Source/WebKit/android/AndroidLog.h
+++ b/Source/WebKit/android/AndroidLog.h
@@ -53,7 +53,12 @@ extern FILE* gRenderTreeFile;
#define DISPLAY_TREE_LOG_FILE "/sdcard/displayTree.txt"
#define LAYERS_TREE_LOG_FILE "/sdcard/layersTree.plist"
-#define TRACE_METHOD() ScopedTrace __st(ATRACE_TAG_WEBVIEW, __func__);
+#define FLOAT_RECT_FORMAT "[x=%.2f,y=%.2f,w=%.2f,h=%.2f]"
+#define FLOAT_RECT_ARGS(fr) fr.x(), fr.y(), fr.width(), fr.height()
+#define INT_RECT_FORMAT "[x=%d,y=%d,w=%d,h=%d]"
+#define INT_RECT_ARGS(ir) ir.x(), ir.y(), ir.width(), ir.height()
+
+#define TRACE_METHOD() android::ScopedTrace __st(ATRACE_TAG_WEBVIEW, __func__);
#define TIME_METHOD() MethodTimer __method_timer(__func__)
class MethodTimer {
diff --git a/Source/WebKit/android/jni/PicturePile.cpp b/Source/WebKit/android/jni/PicturePile.cpp
new file mode 100644
index 0000000..9ca3588
--- /dev/null
+++ b/Source/WebKit/android/jni/PicturePile.cpp
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2012, 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.
+ */
+
+#define LOG_TAG "PicturePile"
+#define LOG_NDEBUG 1
+
+#include "config.h"
+#include "PicturePile.h"
+
+#include "AndroidLog.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "PlatformGraphicsContextSkia.h"
+#include "SkCanvas.h"
+#include "SkNWayCanvas.h"
+#include "SkPicture.h"
+#include "SkPixelRef.h"
+#include "SkRect.h"
+#include "SkRegion.h"
+
+#define ENABLE_PRERENDERED_INVALS true
+#define MAX_OVERLAP_COUNT 2
+#define MAX_OVERLAP_AREA .7
+
+namespace WebCore {
+
+static SkIRect toSkIRect(const IntRect& rect) {
+ return SkIRect::MakeXYWH(rect.x(), rect.y(), rect.width(), rect.height());
+}
+
+static IntRect extractClipBounds(SkCanvas* canvas, const IntSize& size) {
+ SkRect clip;
+ canvas->getClipBounds(&clip);
+ clip.intersect(0, 0, size.width(), size.height());
+ return enclosingIntRect(clip);
+}
+
+PicturePile::PicturePile(const PicturePile& other)
+ : m_size(other.m_size)
+ , m_pile(other.m_pile)
+ , m_webkitInvals(other.m_webkitInvals)
+{
+}
+
+PicturePile::PicturePile(SkPicture* picture)
+{
+ m_size = IntSize(picture->width(), picture->height());
+ PictureContainer pc(IntRect(0, 0, m_size.width(), m_size.height()));
+ pc.picture = picture;
+ pc.dirty = false;
+ m_pile.append(pc);
+}
+
+void PicturePile::draw(SkCanvas* canvas)
+{
+ /* Loop down recursively, subtracting the previous clip from the SkRegion,
+ * stopping when the SkRegion is empty. This will still draw back-to-front,
+ * but it will clip out anything obscured. For performance reasons we use
+ * the rect bounds of the SkRegion for the clip, so this still can't be
+ * used for translucent surfaces
+ */
+ TRACE_METHOD();
+ IntRect clipBounds = extractClipBounds(canvas, m_size);
+ SkRegion clipRegion(toSkIRect(clipBounds));
+ drawWithClipRecursive(canvas, clipRegion, m_pile.size() - 1);
+}
+
+void PicturePile::clearPrerenders()
+{
+ for (size_t i = 0; i < m_pile.size(); i++)
+ m_pile[i].prerendered.clear();
+}
+
+void PicturePile::drawWithClipRecursive(SkCanvas* canvas, SkRegion& clipRegion,
+ int index)
+{
+ // TODO: Add some debug visualizations of this
+ if (index < 0 || clipRegion.isEmpty())
+ return;
+ PictureContainer& pc = m_pile[index];
+ IntRect intersection = clipRegion.getBounds();
+ intersection.intersect(pc.area);
+ if (pc.picture && !intersection.isEmpty()) {
+ clipRegion.op(intersection, SkRegion::kDifference_Op);
+ drawWithClipRecursive(canvas, clipRegion, index - 1);
+ int saved = canvas->save();
+ canvas->clipRect(intersection);
+ canvas->translate(pc.area.x(), pc.area.y());
+ canvas->drawPicture(*pc.picture);
+ canvas->restoreToCount(saved);
+ } else
+ drawWithClipRecursive(canvas, clipRegion, index - 1);
+}
+
+// Used by WebViewCore
+void PicturePile::invalidate(const IntRect& dirtyRect)
+{
+ // This will typically happen if the document has been resized but we haven't
+ // drawn yet. As the first draw after a size change will do a full inval anyway,
+ // don't bother tracking individual rects
+ // TODO: Instead of clipping here, we should take the invals as given
+ // and when the size changes just inval the deltas. This prevents a full
+ // redraw for a page that grows
+ IntRect inval = dirtyRect;
+ inval.intersect(IntRect(0, 0, m_size.width(), m_size.height()));
+ if (inval.isEmpty()) {
+ ALOGV("Rejecting inval " INT_RECT_FORMAT, INT_RECT_ARGS(dirtyRect));
+ return;
+ }
+ // TODO: Support multiple non-intersecting webkit invals
+ if (m_webkitInvals.size())
+ m_webkitInvals[0].unite(inval);
+ else
+ m_webkitInvals.append(inval);
+}
+
+void PicturePile::setSize(const IntSize& size)
+{
+ if (m_size == size)
+ return;
+ m_size = size;
+ // TODO: See above about just adding invals for new content
+ m_pile.clear();
+ m_webkitInvals.clear();
+ IntRect area(0, 0, size.width(), size.height());
+ m_webkitInvals.append(area);
+ m_pile.append(area);
+}
+
+void PicturePile::updatePicturesIfNeeded(PicturePainter* painter)
+{
+ applyWebkitInvals();
+ for (size_t i = 0; i < m_pile.size(); i++) {
+ PictureContainer& pc = m_pile[i];
+ if (pc.dirty)
+ updatePicture(painter, pc);
+ }
+}
+
+void PicturePile::updatePicture(PicturePainter* painter, PictureContainer& pc)
+{
+ /* The ref counting here is a bit unusual. What happens is begin/end recording
+ * will ref/unref the recording canvas. However, 'canvas' might be pointing
+ * at an SkNWayCanvas instead of the recording canvas, which needs to be
+ * unref'd. Thus what we do is ref the recording canvas so that we can
+ * always unref whatever canvas we have at the end.
+ */
+ TRACE_METHOD();
+ SkPicture* picture = new SkPicture();
+ SkCanvas* canvas = picture->beginRecording(pc.area.width(), pc.area.height(),
+ SkPicture::kUsePathBoundsForClip_RecordingFlag);
+ SkSafeRef(canvas);
+ canvas->translate(-pc.area.x(), -pc.area.y());
+ IntRect drawArea = pc.area;
+ if (pc.prerendered.get()) {
+ SkCanvas* prerender = painter->createPrerenderCanvas(pc.prerendered.get());
+ if (!prerender) {
+ ALOGV("Failed to create prerendered for " INT_RECT_FORMAT,
+ INT_RECT_ARGS(pc.prerendered->area));
+ pc.prerendered.clear();
+ } else {
+ drawArea.unite(pc.prerendered->area);
+ SkNWayCanvas* nwayCanvas = new SkNWayCanvas(drawArea.width(), drawArea.height());
+ nwayCanvas->addCanvas(canvas);
+ nwayCanvas->addCanvas(prerender);
+ SkSafeUnref(canvas);
+ SkSafeUnref(prerender);
+ canvas = nwayCanvas;
+ }
+ }
+ WebCore::PlatformGraphicsContextSkia pgc(canvas);
+ WebCore::GraphicsContext gc(&pgc);
+ ALOGV("painting picture: " INT_RECT_FORMAT, INT_RECT_ARGS(drawArea));
+ painter->paintContents(&gc, drawArea);
+ SkSafeUnref(canvas);
+ picture->endRecording();
+
+ SkSafeUnref(pc.picture);
+ pc.picture = picture;
+ pc.dirty = false;
+}
+
+void PicturePile::reset()
+{
+ m_size = IntSize(0,0);
+ m_pile.clear();
+ m_webkitInvals.clear();
+}
+
+void PicturePile::applyWebkitInvals()
+{
+ m_dirtyRegion.setEmpty();
+ if (!m_webkitInvals.size())
+ return;
+ // Build the invals (TODO: Support multiple inval regions)
+ IntRect inval = m_webkitInvals[0];
+ m_dirtyRegion.setRect(toSkIRect(inval));
+ for (size_t i = 1; i < m_webkitInvals.size(); i++) {
+ inval.unite(m_webkitInvals[i]);
+ m_dirtyRegion.op(toSkIRect(m_webkitInvals[i]), SkRegion::kUnion_Op);
+ }
+ m_webkitInvals.clear();
+ ALOGV("Webkit inval: " INT_RECT_FORMAT, INT_RECT_ARGS(inval));
+ if (inval.isEmpty())
+ return;
+
+ // Find the overlaps
+ Vector<int> overlaps;
+ for (size_t i = 0; i < m_pile.size(); i++) {
+ PictureContainer& pc = m_pile[i];
+ if (pc.area.contains(inval)) {
+ if (pc.dirty) {
+ ALOGV("Found already dirty intersection");
+ return;
+ }
+ if (pc.area == inval) {
+ appendToPile(inval);
+ return;
+ }
+ // Don't count the base surface as an overlap
+ if (pc.area.size() != m_size)
+ overlaps.append(i);
+ } else if (pc.area.intersects(inval))
+ overlaps.append(i);
+ }
+
+ if (overlaps.size() >= MAX_OVERLAP_COUNT) {
+ ALOGV("Exceeds overlap count");
+ IntRect overlap = inval;
+ for (int i = (int) overlaps.size() - 1; i >= 0; i--) {
+ overlap.unite(m_pile[overlaps[i]].area);
+ m_pile.remove(overlaps[i]);
+ }
+ float overlapArea = overlap.width() * overlap.height();
+ float totalArea = m_size.width() * m_size.height();
+ if (overlapArea / totalArea > MAX_OVERLAP_AREA)
+ overlap = IntRect(0, 0, m_size.width(), m_size.height());
+ appendToPile(overlap, inval);
+ return;
+ }
+
+ // Append!
+ appendToPile(inval);
+}
+
+void PicturePile::appendToPile(const IntRect& inval, const IntRect& originalInval)
+{
+ ALOGV("Adding inval " INT_RECT_FORMAT " for original inval " INT_RECT_FORMAT,
+ INT_RECT_ARGS(inval), INT_RECT_ARGS(originalInval));
+ // Remove any entries this obscures
+ for (int i = (int) m_pile.size() - 1; i >= 0; i--) {
+ if (inval.contains(m_pile[i].area))
+ m_pile.remove(i);
+ }
+ PictureContainer container(inval);
+ if (ENABLE_PRERENDERED_INVALS) {
+ container.prerendered = PrerenderedInval::create(originalInval.isEmpty()
+ ? inval : originalInval);
+ }
+ m_pile.append(container);
+}
+
+PrerenderedInval* PicturePile::prerenderedInvalForArea(const IntRect& area)
+{
+ ALOGV("Checking for prerendered inval for area " INT_RECT_FORMAT,
+ INT_RECT_ARGS(area));
+ for (int i = (int) m_pile.size() - 1; i >= 0; i--) {
+ if (m_pile[i].area.intersects(area)) {
+ RefPtr<PrerenderedInval> inval = m_pile[i].prerendered;
+ if (inval.get() && inval->area.contains(area)) {
+ ALOGV("Returning prerendered %p for area " INT_RECT_FORMAT,
+ m_pile[i].prerendered.get(), INT_RECT_ARGS(area));
+ return inval.get();
+ }
+ if (inval.get()) {
+ ALOGV("Prerendered area doesn't contain requested area; prerendered="
+ INT_RECT_FORMAT, INT_RECT_ARGS(inval->area));
+ } else
+ ALOGV("No prerendered in intersection");
+ return 0;
+ }
+ }
+ ALOGV("No containers found");
+ return 0;
+}
+
+} // namespace WebCore
diff --git a/Source/WebKit/android/jni/PicturePile.h b/Source/WebKit/android/jni/PicturePile.h
new file mode 100644
index 0000000..b28a792
--- /dev/null
+++ b/Source/WebKit/android/jni/PicturePile.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2012, 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 PicturePile_h
+#define PicturePile_h
+
+#include "IntRect.h"
+#include "IntSize.h"
+#include "PrerenderedInval.h"
+#include "SkBitmap.h"
+#include "SkRegion.h"
+#include "SkRefCnt.h"
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/ThreadSafeRefCounted.h>
+#include <wtf/Vector.h>
+
+class SkPicture;
+class SkCanvas;
+
+namespace WebCore {
+
+class GraphicsContext;
+
+class PicturePainter {
+public:
+ virtual void paintContents(GraphicsContext* gc, IntRect& dirty) = 0;
+ virtual SkCanvas* createPrerenderCanvas(PrerenderedInval* prerendered)
+ {
+ return 0;
+ }
+ virtual ~PicturePainter() {}
+};
+
+class PictureContainer {
+public:
+ SkPicture* picture;
+ IntRect area;
+ bool dirty;
+ RefPtr<PrerenderedInval> prerendered;
+
+ PictureContainer(const IntRect& area)
+ : picture(0)
+ , area(area)
+ , dirty(true)
+ {}
+
+ PictureContainer(const PictureContainer& other)
+ : picture(other.picture)
+ , area(other.area)
+ , dirty(other.dirty)
+ , prerendered(other.prerendered)
+ {
+ SkSafeRef(picture);
+ }
+
+ ~PictureContainer()
+ {
+ SkSafeUnref(picture);
+ }
+};
+
+class PicturePile {
+public:
+ PicturePile() {}
+ PicturePile(const PicturePile& other);
+ PicturePile(SkPicture* picture);
+
+ const IntSize& size() { return m_size; }
+
+ void clearPrerenders();
+
+ // used by PicturePileLayerContents
+ void draw(SkCanvas* canvas);
+
+ // Used by WebViewCore
+ void invalidate(const IntRect& dirtyRect);
+ void setSize(const IntSize& size);
+ void updatePicturesIfNeeded(PicturePainter* painter);
+ void reset();
+ SkRegion& dirtyRegion() { return m_dirtyRegion; }
+ PrerenderedInval* prerenderedInvalForArea(const IntRect& area);
+
+private:
+ void applyWebkitInvals();
+ void updatePicture(PicturePainter* painter, PictureContainer& container);
+ void appendToPile(const IntRect& inval, const IntRect& originalInval = IntRect());
+ void drawWithClipRecursive(SkCanvas* canvas, SkRegion& clipRegion, int index);
+
+ IntSize m_size;
+ Vector<PictureContainer> m_pile;
+ Vector<IntRect> m_webkitInvals;
+ SkRegion m_dirtyRegion;
+};
+
+} // namespace android
+
+#endif // PicturePile_h
diff --git a/Source/WebKit/android/jni/PictureSet.cpp b/Source/WebKit/android/jni/PictureSet.cpp
deleted file mode 100644
index 8beb0ef..0000000
--- a/Source/WebKit/android/jni/PictureSet.cpp
+++ /dev/null
@@ -1,1244 +0,0 @@
-/*
- * Copyright 2008, 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.
- */
-
-#define LOG_TAG "PictureSet"
-#define LOG_NDEBUG 1
-
-#include "config.h"
-#include "PictureSet.h"
-
-#include "AndroidLog.h"
-#include "android_graphics.h"
-#include "SkBounder.h"
-#include "SkCanvas.h"
-#include "SkPicture.h"
-#include "SkRect.h"
-#include "SkRegion.h"
-#include "SkStream.h"
-
-#include "PlatformGraphicsContext.h"
-
-#define MAX_DRAW_TIME 100
-#define MIN_SPLITTABLE 400
-#define MAX_ADDITIONAL_AREA 0.65
-#define MAX_ADDITIONAL_PICTURES 32
-
-#define BUCKET_SIZE 1024
-#define MAX_BUCKET_COUNT_X 16
-#define MAX_BUCKET_COUNT_Y 64
-
-#if PICTURE_SET_DEBUG
-class MeasureStream : public SkWStream {
-public:
- MeasureStream() : mTotal(0) {}
- virtual bool write(const void* , size_t size) {
- mTotal += size;
- return true;
- }
- size_t mTotal;
-};
-#endif
-
-namespace android {
-
-PictureSet::PictureSet() :
-#ifdef FAST_PICTURESET
- mBucketSizeX(BUCKET_SIZE), mBucketSizeY(BUCKET_SIZE),
- mBucketCountX(0), mBucketCountY(0),
-#endif
- mHeight(0), mWidth(0)
-{
- setDimensions(0, 0);
- mBaseArea = mAdditionalArea = 0;
-}
-
-PictureSet::PictureSet(SkPicture* picture) :
-#ifdef FAST_PICTURESET
- mBucketSizeX(BUCKET_SIZE), mBucketSizeY(BUCKET_SIZE),
- mBucketCountX(0), mBucketCountY(0),
-#endif
- mHeight(0), mWidth(0)
-{
- mBaseArea = mAdditionalArea = 0;
- if (!picture) {
- setDimensions(0, 0);
- return;
- }
- setDimensions(picture->width(), picture->height());
- mBaseArea = mWidth * mHeight;
-#ifdef FAST_PICTURESET
- SkIRect area;
- area.set(0, 0, mWidth, mHeight);
- splitAdd(area);
- WTF::Vector<Bucket*>* buckets = bucketsToUpdate();
- for (unsigned int i = 0; i < buckets->size(); i++) {
- Bucket* bucket = (*buckets)[i];
- for (unsigned int j = 0; j < bucket->size(); j++) {
- BucketPicture& bucketPicture = (*bucket)[j];
- const SkIRect& inval = bucketPicture.mRealArea;
- SkPicture *splitPicture = new SkPicture();
- SkCanvas *canvas = splitPicture->beginRecording(
- inval.width(), inval.height(),
- SkPicture::kUsePathBoundsForClip_RecordingFlag);
- canvas->translate(-inval.fLeft, -inval.fTop);
- picture->draw(canvas);
- splitPicture->endRecording();
- SkSafeUnref(bucketPicture.mPicture);
- bucketPicture.mPicture = splitPicture;
- }
- }
- buckets->clear();
-#else
- Pictures pictureAndBounds;
- pictureAndBounds.mPicture = picture;
- SkSafeRef(pictureAndBounds.mPicture);
- pictureAndBounds.mEmpty = false;
- pictureAndBounds.mArea.set(0, 0, mWidth, mHeight);
- pictureAndBounds.mSplit = false;
- pictureAndBounds.mBase = true;
- pictureAndBounds.mElapsed = 0;
- pictureAndBounds.mWroteElapsed = false;
- mPictures.append(pictureAndBounds);
-#endif // FAST_PICTURESET
-}
-
-PictureSet::~PictureSet()
-{
- clear();
-}
-
-#ifdef FAST_PICTURESET
-#else
-void PictureSet::add(const Pictures* temp)
-{
- Pictures pictureAndBounds = *temp;
- SkSafeRef(pictureAndBounds.mPicture);
-#ifdef CONTEXT_RECORDING
- SkSafeRef(pictureAndBounds.mGraphicsOperationCollection);
-#endif
- pictureAndBounds.mWroteElapsed = false;
- mPictures.append(pictureAndBounds);
-}
-#endif // FAST_PICTURESET
-
-void PictureSet::add(const SkRegion& area, uint32_t elapsed, bool split)
-{
- if (area.isRect()) {
-#ifdef FAST_PICTURESET
- splitAdd(area.getBounds());
-#else
- add(area.getBounds(), elapsed, split, false);
-#endif // FAST_PICTURESET
- } else {
- SkRegion::Iterator cliperator(area);
- while (!cliperator.done()) {
- SkIRect ir = cliperator.rect();
-#ifdef FAST_PICTURESET
- splitAdd(ir);
-#else
- add(ir, elapsed, split, false);
-#endif // FAST_PICTURESET
- cliperator.next();
- }
- }
-}
-
-#ifdef FAST_PICTURESET
-
-Bucket* PictureSet::getBucket(int x, int y)
-{
- // only create buckets for valid, positive coordinates, ignore and return
- // NULL otherwise
- if (x < 0 || y < 0)
- return 0;
-
- BucketPosition position(x+1, y+1);
- if (!mBuckets.contains(position)) {
- ALOGV("PictureSet::getBucket(%d, %d) adding new bucket", x, y);
- Bucket* bucket = new Bucket();
- mBuckets.add(position, bucket);
- }
- return mBuckets.get(position);
-}
-
-void PictureSet::displayBucket(Bucket* bucket)
-{
- BucketPicture* first = bucket->begin();
- BucketPicture* last = bucket->end();
- for (BucketPicture* current = first; current != last; current++) {
- ALOGD("- in %x, bucketPicture %d,%d,%d,%d - %dx%d, picture: %x, base: %x",
- bucket,
- current->mArea.fLeft,
- current->mArea.fTop,
- current->mArea.fRight,
- current->mArea.fBottom,
- current->mArea.width(),
- current->mArea.height(),
- current->mPicture,
- current->mBase);
- }
-}
-
-void PictureSet::displayBuckets()
-{
- ALOGD("\n\n****** DISPLAY BUCKETS ON PictureSet %x ******", this);
- for (BucketMap::iterator iter = mBuckets.begin(); iter != mBuckets.end(); ++iter) {
- ALOGD("\n*** Bucket %x for %d, %d", iter->second, iter->first.first, iter->first.second);
- displayBucket(iter->second);
- }
- ALOGD("\n****** END OF DISPLAY BUCKETS ******\n\n");
-}
-
-// When we receive an inval in a Bucket, we try to see if we intersect with
-// existing invals/pictures in the Bucket.
-void PictureSet::addToBucket(Bucket* bucket, int dx, int dy, SkIRect& rect)
-{
- bool resetBase = false;
-
- SkIRect totalArea = rect;
- BucketPicture* first = bucket->begin();
- BucketPicture* last = bucket->end();
-
- // If the inval covers a large area of the base inval, let's repaint the
- // entire bucket.
- if (rect.width() * rect.height() > MAX_ADDITIONAL_AREA * mBucketSizeX * mBucketSizeY)
- resetBase = true;
-
- // let's gather all the BucketPicture intersecting with the new invalidated
- // area, collect their area and remove their picture
- for (BucketPicture* current = first; current != last; current++) {
- bool remove = resetBase;
- bool intersect = false;
-
- if (!remove)
- intersect = SkIRect::Intersects(current->mArea, rect);
- // If the current picture is not a base, and we intersect, remove it
- if (!remove && !current->mBase && intersect)
- remove = true;
- // If the current picture is a base, check if the new inval completely
- // contains the base, and if so remove it.
- if (!remove && current->mBase && rect.contains(current->mArea))
- remove = true;
- // If the current picture is a base and it intersects,
- // also check that it fully covers the bucket -- otherwise,
- // let's aggregate it with the new inval.
- if (!remove && current->mBase && intersect
- && (current->mArea.width() < mBucketSizeX || current->mArea.height() < mBucketSizeY)) {
- remove = true;
- }
-
- if (remove) {
- totalArea.join(current->mArea);
- current->mBase = false;
- current->mArea.setEmpty();
- SkSafeUnref(current->mPicture);
- current->mPicture = 0;
- }
- }
-
- // Now, let's add the new BucketPicture to the list, with the correct
- // area that needs to be repainted
- SkRegion region;
- SkIRect area = totalArea;
- area.offset(dx, dy);
- BucketPicture picture = { 0, totalArea, area, false };
-
- bucket->append(picture);
-
- first = bucket->begin();
- last = bucket->end();
-
- bool clearUp = false;
- if (last - first > MAX_ADDITIONAL_PICTURES) {
- // too many pictures in the bucket, let's collapse
- clearUp = true;
- }
-
- float bucketBaseArea = 0;
- float bucketAdditionalArea = 0;
- for (BucketPicture* current = first; current != last; current++) {
- float area = current->mArea.width() * current->mArea.height();
- if (current->mBase)
- bucketBaseArea += area;
- else
- bucketAdditionalArea += area;
- }
-
- if (bucketBaseArea > 0 && bucketBaseArea * MAX_ADDITIONAL_AREA <= bucketAdditionalArea) {
- // additional area too large, not worth maintaining
- clearUp = true;
- }
-
- // To clear things up, we just need to mark the pictures' area as empty
- // We only keep the base surface.
- if (clearUp) {
- for (BucketPicture* current = first; current != last; current++) {
- if (!current->mBase)
- current->mArea.setEmpty();
- SkSafeUnref(current->mPicture);
- current->mPicture = 0;
- }
- }
-
- // let's do a pass to collapse out empty areas
- BucketPicture* writer = first;
- for (BucketPicture* current = first; current != last; current++) {
- if (current && current->mArea.isEmpty())
- continue;
- *writer++ = *current;
- }
-
- bucket->shrink(writer - first);
-
- // let's recompute the bases
- first = bucket->begin();
- last = bucket->end();
- SkRegion drawn;
- drawn.setEmpty();
- for (BucketPicture* current = first; current != last; current++) {
- if (drawn.contains(current->mArea) == false) {
- current->mBase = true;
- }
- drawn.op(current->mArea, SkRegion::kUnion_Op);
- }
-}
-
-void PictureSet::gatherBucketsForArea(WTF::Vector<Bucket*>& list, const SkIRect& rect)
-{
- ALOGV("\n--- gatherBucketsForArea for rect %d, %d, %d, %d (%d x %d)",
- rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
- rect.width(), rect.height());
-
- if (!mBucketSizeX || !mBucketSizeY) {
- ALOGD("PictureSet::gatherBucketsForArea() called with bad bucket size: x=%d y=%d",
- mBucketSizeX, mBucketSizeY);
- return;
- }
-
- int x = rect.fLeft;
- int y = rect.fTop;
- int firstTileX = rect.fLeft / mBucketSizeX;
- int firstTileY = rect.fTop / mBucketSizeY;
- int lastTileX = rect.fRight / mBucketSizeX;
- int lastTileY = rect.fBottom / mBucketSizeY;
-
- for (int i = firstTileX; i <= lastTileX; i++) {
- for (int j = firstTileY; j <= lastTileY; j++) {
- Bucket* bucket = getBucket(i, j);
- ALOGV("gather bucket %x for %d, %d", bucket, i+1, j+1);
- if (bucket)
- list.append(bucket);
- }
- }
-}
-
-// When we receive a new inval rect, we first find the Buckets that intersect
-// with it; then we split the original inval into a serie of invals (one for
-// each Bucket we intersect with). We then send that inval to the Bucket.
-void PictureSet::splitAdd(const SkIRect& rect)
-{
- ALOGV("\n--- splitAdd for rect %d, %d, %d, %d (%d x %d)",
- rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
- rect.width(), rect.height());
-
- if (!mBucketSizeX || !mBucketSizeY) {
- ALOGD("PictureSet::splitAdd() called with bad bucket size: x=%d y=%d",
- mBucketSizeX, mBucketSizeY);
- return;
- }
-
- // TODO: reuse gatherBucketsForArea() (change Bucket to be a class)
- int x = rect.fLeft;
- int y = rect.fTop;
- int firstTileX = rect.fLeft / mBucketSizeX;
- int firstTileY = rect.fTop / mBucketSizeY;
- int lastTileX = rect.fRight / mBucketSizeX;
- int lastTileY = rect.fBottom / mBucketSizeY;
-
- ALOGV("--- firstTile(%d, %d) lastTile(%d, %d)",
- firstTileX, firstTileY,
- lastTileX, lastTileY);
-
- for (int i = firstTileX; i <= lastTileX; i++) {
- for (int j = firstTileY; j <= lastTileY; j++) {
- Bucket* bucket = getBucket(i, j);
- if (!bucket)
- continue;
-
- SkIRect newRect;
- int deltaX = i * mBucketSizeX;
- int deltaY = j * mBucketSizeY;
- int left = (i == firstTileX) ? rect.fLeft - deltaX : 0;
- int top = (j == firstTileY) ? rect.fTop - deltaY : 0;
- int right = (i == lastTileX) ? rect.fRight % mBucketSizeX : mBucketSizeX;
- int bottom = (j == lastTileY) ? rect.fBottom % mBucketSizeY : mBucketSizeY;
-
- newRect.set(left, top, right, bottom);
- addToBucket(bucket, deltaX, deltaY, newRect);
- mUpdatedBuckets.append(bucket);
- }
- }
-
- ALOGV("--- splitAdd DONE\n");
-}
-
-#endif // FAST_PICTURESET
-
-// This function is used to maintain the list of Pictures.
-// Pictures contain an SkPicture covering a specific area; some
-// Pictures are "base" Pictures -- i.e. there is no Pictures
-// underneath them.
-// The idea here is to keep a balance between the number of Pictures
-// we have (more Pictures slow us down) and the area of Pictures that
-// need to be repainted (obviously, smaller areas are better).
-// To do so, we try to not update/repaint the base pictures -- by
-// construction, they usually cover a large area (the entire page).
-// We only reset a base picture if the new invalidated area entirely
-// contains it.
-// Most of the time we thus work on smaller pictures on top of the
-// base ones; We compute the total area of all pictures intersecting
-// with the passed invalidated area (as they would need to be invalidated),
-// and use that as the basis for the correct area we want to invalidate
-// (we then can simply delete the pictures we intersect with).
-// In addition, we do a couple of things to limit the total number of pictures
-// we keep in the list:
-// - if the total area of additional textures reach 65% of the base pictures,
-// we delete the additional pictures and mark the base pictures as
-// needing a full repaint
-// - we limit the number of pictures to 32 -- above that, we do the same
-// things (deleting additional pictures + full repaint of base pictures)
-#ifdef FAST_PICTURESET
-#else
-void PictureSet::add(const SkIRect& area, uint32_t elapsed, bool split, bool empty)
-{
- bool checkForNewBases = false;
-
- Pictures* first = mPictures.begin();
- Pictures* last = mPictures.end();
-#ifdef DEBUG
- ALOGV("--- before adding the new inval ---");
- for (Pictures* working = mPictures.begin(); working != mPictures.end(); working++) {
- SkIRect currentArea = working->mArea;
- ALOGV("picture %d (%d, %d, %d, %d - %d x %d) base: %c",
- working - first,
- currentArea.fLeft, currentArea.fTop, currentArea.fRight, currentArea.fBottom,
- currentArea.width(), currentArea.height(),
- working->mBase ? 'Y' : 'N');
- }
- ALOGV("----------------------------------");
-#endif
-
- // let's gather all the Pictures intersecting with the new invalidated
- // area, collect their area and remove their picture
- SkIRect totalArea = area;
- for (Pictures* working = first; working != last; working++) {
- SkIRect inval = area;
- bool remove = false;
- if (!working->mBase && SkIRect::Intersects(working->mArea, inval))
- remove = true;
- if (working->mBase) {
- SkIRect baseArea = working->mArea;
- if (area.contains(baseArea)) {
- remove = true;
- checkForNewBases = true;
- }
- }
-
- if (remove) {
- SkIRect currentArea = working->mArea;
- if (working->mBase)
- mBaseArea -= currentArea.width() * currentArea.height();
- else
- mAdditionalArea -= currentArea.width() * currentArea.height();
-
- totalArea.join(currentArea);
- ALOGV("picture %d (%d, %d, %d, %d - %d x %d) intersects with the new inval area (%d, %d, %d, %d - %d x %d)",
- working - first,
- currentArea.fLeft, currentArea.fTop, currentArea.fRight, currentArea.fBottom,
- currentArea.width(), currentArea.height(),
- inval.fLeft, inval.fTop, inval.fRight, inval.fBottom,
- inval.width(), inval.height());
- working->mArea.setEmpty();
- SkSafeUnref(working->mPicture);
- working->mPicture = 0;
-#ifdef CONTEXT_RECORDING
- SkSafeUnref(working->mGraphicsOperationCollection);
- working->mGraphicsOperationCollection = 0;
-#endif
- }
- }
-
- // Now we can add the new Picture to the list, with the correct area
- // that need to be repainted
- Pictures pictureAndBounds = {totalArea, 0,
-#ifdef CONTEXT_RECORDING
- 0,
-#endif
- totalArea, elapsed, split, false, false, empty};
-
-#ifdef FAST_PICTURESET
- if (mPictures.size() == 0)
- checkForNewBases = true;
-#endif
-
- if (!size()) {
- pictureAndBounds.mBase = true;
- mBaseArea = totalArea.width() * totalArea.height();
- mAdditionalArea = 0;
- mPictures.append(pictureAndBounds);
- return;
- }
- mPictures.append(pictureAndBounds);
- mAdditionalArea += totalArea.width() * totalArea.height();
- last = mPictures.end();
- first = mPictures.begin();
-
- // Then, let's see if we have to clear up the pictures in order to keep
- // the total number of pictures under our limit
- bool clearUp = false;
- if (last - first > MAX_ADDITIONAL_PICTURES) {
- ALOGV("--- too many pictures, only keeping the bases : %d", last - first);
- clearUp = true;
- }
-
- if (!clearUp) {
- if (mBaseArea > 0 && mBaseArea * MAX_ADDITIONAL_AREA <= mAdditionalArea) {
- ALOGV("+++ the sum of the additional area is > %.2f\% of the base Area (%.2f (%.2f) <= %.2f",
- MAX_ADDITIONAL_AREA * 100, mBaseArea * 0.65, mBaseArea, mAdditionalArea);
- clearUp = true;
- }
- }
-
- if (clearUp) {
- for (Pictures* working = mPictures.begin(); working != mPictures.end(); working++) {
- if (!working->mBase)
- working->mArea.setEmpty();
- SkSafeUnref(working->mPicture);
- working->mPicture = 0;
-#ifdef CONTEXT_RECORDING
- SkSafeUnref(working->mGraphicsOperationCollection);
- working->mGraphicsOperationCollection = 0;
-#endif
- }
- }
-
-#ifdef DEBUG
- ALOGV("--- after adding the new inval, but before collapsing ---");
- for (Pictures* working = mPictures.begin(); working != mPictures.end(); working++) {
- SkIRect currentArea = working->mArea;
- ALOGV("picture %d (%d, %d, %d, %d - %d x %d) base: %c",
- working - first,
- currentArea.fLeft, currentArea.fTop, currentArea.fRight, currentArea.fBottom,
- currentArea.width(), currentArea.height(),
- working->mBase ? 'Y' : 'N');
- }
- ALOGV("----------------------------------");
- ALOGV("let's collapse...");
-#endif
-
- // Finally, let's do a pass to collapse out empty regions
- Pictures* writer = first;
- for (Pictures* working = first; working != last; working++) {
- if (working && working->mArea.isEmpty())
- continue;
- *writer++ = *working;
- }
- ALOGV("shiking of %d elements", writer - first);
- mPictures.shrink(writer - first);
-
-#ifdef DEBUG
- ALOGV("--- after adding the new inval ---");
- for (Pictures* working = mPictures.begin(); working != mPictures.end(); working++) {
- SkIRect currentArea = working->mArea;
- ALOGV("picture %d (%d, %d, %d, %d - %d x %d) base: %c picture %x",
- working - first,
- currentArea.fLeft, currentArea.fTop, currentArea.fRight, currentArea.fBottom,
- currentArea.width(), currentArea.height(),
- working->mBase ? 'Y' : 'N', working->mPicture);
- }
- ALOGV("----------------------------------");
-#endif
-
- // Base pictures might have been removed/added -- let's recompute them
- SkRegion drawn;
- if (checkForNewBases) {
- drawn.setEmpty();
- Pictures* last = mPictures.end();
- ALOGV("checkForNewBases...");
- for (Pictures* working = mPictures.begin(); working != last; working++) {
- SkRegion area;
- area.setRect(working->mArea);
- const SkIRect& a = area.getBounds();
- if (drawn.contains(working->mArea) == false) {
- working->mBase = true;
- float area = a.width() * a.height();
- mBaseArea += area;
- mAdditionalArea -= area;
- }
- drawn.op(working->mArea, SkRegion::kUnion_Op);
- }
- }
-
-#ifdef DEBUG
- ALOGV("--- after checking for bases ---");
- for (Pictures* working = mPictures.begin(); working != mPictures.end(); working++) {
- SkIRect currentArea = working->mArea;
- ALOGV("picture %d (%d, %d, %d, %d - %d x %d) base: %c picture %x",
- working - first,
- currentArea.fLeft, currentArea.fTop, currentArea.fRight, currentArea.fBottom,
- currentArea.width(), currentArea.height(),
- working->mBase ? 'Y' : 'N', working->mPicture);
- }
- ALOGV("----------------------------------");
-#endif
-}
-#endif // FAST_PICTURESET
-
-void PictureSet::setDimensions(int width, int height, SkRegion* inval)
-{
- // Note that setDimensions() may be called by our ctor and should behave accordingly
- if (mWidth == width && mHeight == height)
- return;
- DBG_SET_LOGD("%p old:(w=%d,h=%d) new:(w=%d,h=%d)", this,
- mWidth, mHeight, width, height);
- bool clearCache = false;
- if (inval) {
- if (mWidth == width && height > mHeight) { // only grew vertically
- SkIRect rect;
- rect.set(0, mHeight, width, height);
- inval->op(rect, SkRegion::kUnion_Op);
- } else {
- clearCache = true;
- inval->setRect(0, 0, width, height);
- }
- }
-#ifdef FAST_PICTURESET
- // First figure out how large each bucket would be if we used all of the buckets
- int tmpSizeX = (width + MAX_BUCKET_COUNT_X - 1) / MAX_BUCKET_COUNT_X;
- int tmpSizeY = (height + MAX_BUCKET_COUNT_Y - 1) / MAX_BUCKET_COUNT_Y;
-
- // Then round the bucket size up to the nearest chunk
- int bucketSizeX = ((tmpSizeX - 1) / BUCKET_SIZE + 1) * BUCKET_SIZE;
- int bucketSizeY = ((tmpSizeY - 1) / BUCKET_SIZE + 1) * BUCKET_SIZE;
-
- int bucketCountX = (width + bucketSizeX - 1) / bucketSizeX;
- int bucketCountY = (height + bucketSizeY - 1) / bucketSizeY;
-
- // Clear the cache if the horizontal bucket count changed or the vertical
- // count shrank
- if (bucketCountX != mBucketCountX || bucketCountY < mBucketCountY)
- clearCache = true;
-
- // Or if the bucket size changed
- if (bucketSizeX != mBucketSizeX || bucketSizeY != mBucketSizeY)
- clearCache = true;
-
- ALOGV("old width=%d height=%d bucketSizeX=%d bucketSizeY=%d bucketCountX=%d bucketCountY=%d clearCache=%d",
- mWidth, mHeight, mBucketSizeX, mBucketSizeY, mBucketCountX, mBucketCountY, clearCache);
- ALOGV("new width=%d height=%d bucketSizeX=%d bucketSizeY=%d bucketCountX=%d bucketCountY=%d clearCache=%d",
- width, height, bucketSizeX, bucketSizeY, bucketCountX, bucketCountY, clearCache);
-#endif
- if (clearCache)
- clear();
- mWidth = width;
- mHeight = height;
-#ifdef FAST_PICTURESET
- mBucketSizeX = bucketSizeX;
- mBucketSizeY = bucketSizeY;
- mBucketCountX = bucketCountX;
- mBucketCountY = bucketCountY;
-#endif
-}
-
-void PictureSet::clear()
-{
- DBG_SET_LOG("");
-#ifdef FAST_PICTURESET
- for (BucketMap::iterator iter = mBuckets.begin(); iter != mBuckets.end(); ++iter) {
- Bucket* bucket = iter->second;
- BucketPicture* first = bucket->begin();
- BucketPicture* last = bucket->end();
- for (BucketPicture* current = first; current != last; current++) {
- SkSafeUnref(current->mPicture);
- current->mPicture = 0;
- }
- bucket->clear();
- }
- mBuckets.clear();
- mBucketSizeX = mBucketSizeY = BUCKET_SIZE;
-#else
- Pictures* last = mPictures.end();
- for (Pictures* working = mPictures.begin(); working != last; working++) {
- working->mArea.setEmpty();
- SkSafeUnref(working->mPicture);
-#ifdef CONTEXT_RECORDING
- SkSafeUnref(working->mGraphicsOperationCollection);
-#endif
- }
- mPictures.clear();
-#endif // FAST_PICTURESET
- mWidth = mHeight = 0;
-}
-
-uint32_t getThreadMsec()
-{
-#if defined(HAVE_POSIX_CLOCKS)
- struct timespec tm;
-
- clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tm);
- return tm.tv_sec * 1000LL + tm.tv_nsec / 1000000;
-#else
- struct timeval now;
- struct timezone zone;
-
- gettimeofday(&now, &zone);
- return now.tv_sec * 1000LL + now.tv_usec / 1000;
-#endif
-}
-
-bool PictureSet::draw(SkCanvas* canvas)
-{
-#ifdef FAST_PICTURESET
- ALOGV("PictureSet %x draw on canvas %x", this, canvas);
- SkRect bounds;
- if (canvas->getClipBounds(&bounds) == false)
- return false;
- SkIRect irect;
- bounds.roundOut(&irect);
-
- WTF::Vector<Bucket*> list;
- gatherBucketsForArea(list, irect);
-
- ALOGV("PictureSet draw on canvas %x, we have %d buckets", canvas, list.size());
- for (unsigned int i = 0; i < list.size(); i++) {
- Bucket* bucket = list[i];
- ALOGV("We paint using bucket %x with %d pictures", bucket, bucket->size());
- for (unsigned int j = 0; j < bucket->size(); j++) {
- BucketPicture& picture = bucket->at(j);
- if (!picture.mPicture)
- continue;
- int saved = canvas->save();
- SkRect pathBounds;
- pathBounds.set(picture.mRealArea);
- ALOGV("[%d/%d] draw on canvas with clip %d, %d, %d, %d - %d x %d",
- j, bucket->size(),
- picture.mRealArea.fLeft,
- picture.mRealArea.fTop,
- picture.mRealArea.fRight,
- picture.mRealArea.fBottom,
- picture.mRealArea.width(),
- picture.mRealArea.height());
- canvas->clipRect(pathBounds);
- canvas->translate(pathBounds.fLeft, pathBounds.fTop);
- canvas->save();
- canvas->drawPicture(*picture.mPicture);
- canvas->restoreToCount(saved);
- }
- }
- return false;
-
-#else
-
- validate(__FUNCTION__);
- Pictures* first = mPictures.begin();
- Pictures* last = mPictures.end();
- Pictures* working;
- SkRect bounds;
- if (canvas->getClipBounds(&bounds) == false)
- return false;
- SkIRect irect;
- bounds.roundOut(&irect);
- if (!irect.intersect(0, 0, width(), height()))
- return false;
- for (working = last; working != first; ) {
- --working;
- if (working->mArea.contains(irect)) {
-#if PICTURE_SET_DEBUG
- const SkIRect& b = working->mArea;
- DBG_SET_LOGD("contains working->mArea={%d,%d,%d,%d}"
- " irect={%d,%d,%d,%d}", b.fLeft, b.fTop, b.fRight, b.fBottom,
- irect.fLeft, irect.fTop, irect.fRight, irect.fBottom);
-#endif
- first = working;
- break;
- }
- }
- DBG_SET_LOGD("%p first=%d last=%d", this, first - mPictures.begin(),
- last - mPictures.begin());
- uint32_t maxElapsed = 0;
- for (working = first; working != last; working++) {
- SkRegion area;
- area.setRect(working->mArea);
- if (area.quickReject(irect)) {
-#if PICTURE_SET_DEBUG
- const SkIRect& b = area.getBounds();
- DBG_SET_LOGD("[%d] %p quickReject working->mArea={%d,%d,%d,%d}"
- " irect={%d,%d,%d,%d}", working - first, working,
- b.fLeft, b.fTop, b.fRight, b.fBottom,
- irect.fLeft, irect.fTop, irect.fRight, irect.fBottom);
-#endif
- working->mElapsed = 0;
- continue;
- }
- int saved = canvas->save();
- SkRect pathBounds;
- if (area.isComplex()) {
- SkPath pathClip;
- area.getBoundaryPath(&pathClip);
- canvas->clipPath(pathClip);
- pathBounds = pathClip.getBounds();
- } else {
- pathBounds.set(area.getBounds());
- canvas->clipRect(pathBounds);
- }
- canvas->translate(pathBounds.fLeft, pathBounds.fTop);
- canvas->save();
- uint32_t startTime = getThreadMsec();
-
-#ifdef CONTEXT_RECORDING
- WebCore::PlatformGraphicsContextSkia context(canvas);
- working->mGraphicsOperationCollection->apply(&context);
-#else
- canvas->drawPicture(*working->mPicture);
-#endif
-
- size_t elapsed = working->mElapsed = getThreadMsec() - startTime;
- working->mWroteElapsed = true;
- if (maxElapsed < elapsed && (pathBounds.width() >= MIN_SPLITTABLE ||
- pathBounds.height() >= MIN_SPLITTABLE))
- maxElapsed = elapsed;
- canvas->restoreToCount(saved);
-#define DRAW_TEST_IMAGE 01
-#if DRAW_TEST_IMAGE && PICTURE_SET_DEBUG
- SkColor color = 0x3f000000 | (0xffffff & (unsigned) working);
- canvas->drawColor(color);
- SkPaint paint;
- color ^= 0x00ffffff;
- paint.setColor(color);
- char location[256];
- for (int x = area.getBounds().fLeft & ~0x3f;
- x < area.getBounds().fRight; x += 0x40) {
- for (int y = area.getBounds().fTop & ~0x3f;
- y < area.getBounds().fBottom; y += 0x40) {
- int len = snprintf(location, sizeof(location) - 1, "(%d,%d)", x, y);
- canvas->drawText(location, len, x, y, paint);
- }
- }
-#endif
- DBG_SET_LOGD("[%d] %p working->mArea={%d,%d,%d,%d} elapsed=%d base=%s",
- working - first, working,
- area.getBounds().fLeft, area.getBounds().fTop,
- area.getBounds().fRight, area.getBounds().fBottom,
- working->mElapsed, working->mBase ? "true" : "false");
- }
- // dump(__FUNCTION__);
- return maxElapsed >= MAX_DRAW_TIME;
-#endif // FAST_PICTURESET
-}
-
-void PictureSet::dump(const char* label) const
-{
-#if PICTURE_SET_DUMP
- DBG_SET_LOGD("%p %s (%d) (w=%d,h=%d)", this, label, mPictures.size(),
- mWidth, mHeight);
- const Pictures* last = mPictures.end();
- for (const Pictures* working = mPictures.begin(); working != last; working++) {
- const SkIRect& bounds = working->mArea.getBounds();
- const SkIRect& unsplit = working->mUnsplit;
- MeasureStream measure;
- if (working->mPicture != NULL)
- working->mPicture->serialize(&measure);
- ALOGD(" [%d]"
- " mArea.bounds={%d,%d,r=%d,b=%d}"
- " mPicture=%p"
- " mUnsplit={%d,%d,r=%d,b=%d}"
- " mElapsed=%d"
- " mSplit=%s"
- " mWroteElapsed=%s"
- " mBase=%s"
- " pict-size=%d",
- working - mPictures.begin(),
- bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom,
- working->mPicture,
- unsplit.fLeft, unsplit.fTop, unsplit.fRight, unsplit.fBottom,
- working->mElapsed, working->mSplit ? "true" : "false",
- working->mWroteElapsed ? "true" : "false",
- working->mBase ? "true" : "false",
- measure.mTotal);
- }
-#endif
-}
-
-class IsEmptyBounder : public SkBounder {
- virtual bool onIRect(const SkIRect& rect) {
- return false;
- }
-};
-
-class IsEmptyCanvas : public SkCanvas {
-public:
- IsEmptyCanvas(SkBounder* bounder, SkPicture* picture) :
- mPicture(picture), mEmpty(true) {
- setBounder(bounder);
- }
-
- void notEmpty() {
- mEmpty = false;
- mPicture->abortPlayback();
- }
-
- virtual bool clipPath(const SkPath&, SkRegion::Op) {
- // this can be expensive to actually do, and doesn't affect the
- // question of emptiness, so we make it a no-op
- return true;
- }
-
- virtual void commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* rect,
- const SkMatrix& , const SkPaint& ) {
- if (bitmap.width() <= 1 || bitmap.height() <= 1)
- return;
- DBG_SET_LOGD("abort {%d,%d}", bitmap.width(), bitmap.height());
- notEmpty();
- }
-
- virtual void drawPaint(const SkPaint& paint) {
- }
-
- virtual void drawPath(const SkPath& , const SkPaint& paint) {
- DBG_SET_LOG("abort");
- notEmpty();
- }
-
- virtual void drawPoints(PointMode , size_t , const SkPoint [],
- const SkPaint& paint) {
- }
-
- virtual void drawRect(const SkRect& , const SkPaint& paint) {
- // wait for visual content
- if (paint.getColor() != SK_ColorWHITE)
- notEmpty();
- }
-
- virtual void drawSprite(const SkBitmap& , int , int ,
- const SkPaint* paint = NULL) {
- DBG_SET_LOG("abort");
- notEmpty();
- }
-
- virtual void drawText(const void* , size_t byteLength, SkScalar ,
- SkScalar , const SkPaint& paint) {
- DBG_SET_LOGD("abort %d", byteLength);
- notEmpty();
- }
-
- virtual void drawPosText(const void* , size_t byteLength,
- const SkPoint [], const SkPaint& paint) {
- DBG_SET_LOGD("abort %d", byteLength);
- notEmpty();
- }
-
- virtual void drawPosTextH(const void* , size_t byteLength,
- const SkScalar [], SkScalar ,
- const SkPaint& paint) {
- DBG_SET_LOGD("abort %d", byteLength);
- notEmpty();
- }
-
- virtual void drawTextOnPath(const void* , size_t byteLength,
- const SkPath& , const SkMatrix* ,
- const SkPaint& paint) {
- DBG_SET_LOGD("abort %d", byteLength);
- notEmpty();
- }
-
- virtual void drawPicture(SkPicture& picture) {
- SkCanvas::drawPicture(picture);
- }
-
- SkPicture* mPicture;
- bool mEmpty;
-};
-
-bool PictureSet::emptyPicture(SkPicture* picture) const
-{
- IsEmptyBounder isEmptyBounder;
- IsEmptyCanvas checker(&isEmptyBounder, picture);
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, mWidth, mHeight);
- checker.setBitmapDevice(bitmap);
- checker.drawPicture(*picture);
- return checker.mEmpty;
-}
-
-bool PictureSet::isEmpty() const
-{
-#ifdef FAST_PICTURESET
- // For now, just assume the pictureset is *not* empty
- // if the hashmap contains something
- for (BucketMap::const_iterator iter = mBuckets.begin(); iter != mBuckets.end(); ++iter) {
- if (iter->second->size() > 0)
- return false;
- }
- return true;
-#else
- const Pictures* last = mPictures.end();
- for (const Pictures* working = mPictures.begin(); working != last; working++) {
- if (!working->mEmpty)
- return false;
- }
- return true;
-#endif // FAST_PICTURESET
-}
-
-void PictureSet::set(const PictureSet& src)
-{
- DBG_SET_LOGD("start %p src=%p", this, &src);
- clear();
- setDimensions(src.mWidth, src.mHeight);
-#ifdef FAST_PICTURESET
- ALOGV("\n--- set picture ---");
- for (BucketMap::const_iterator iter = src.mBuckets.begin();
- iter != src.mBuckets.end(); ++iter) {
- Bucket* sourceBucket = iter->second;
- Bucket* targetBucket = getBucket(iter->first.first-1, iter->first.second-1);
- BucketPicture* first = sourceBucket->begin();
- BucketPicture* last = sourceBucket->end();
- ALOGV("set from bucket %x (%d, %d), %d pictures", sourceBucket,
- iter->first.first, iter->first.second, sourceBucket->size());
- for (BucketPicture* current = first; current != last; current++) {
- ALOGV("set picture %x from bucket %x in bucket %x (%d, %d)",
- current->mPicture, sourceBucket, targetBucket,
- iter->first.first, iter->first.second);
- SkSafeRef(current->mPicture);
- BucketPicture picture = { current->mPicture, current->mArea,
- current->mRealArea, current->mBase };
- targetBucket->append(picture);
- }
- }
- ALOGV("--- DONE set picture ---\n");
-#else
- const Pictures* last = src.mPictures.end();
- for (const Pictures* working = src.mPictures.begin(); working != last; working++)
- add(working);
- // dump(__FUNCTION__);
- validate(__FUNCTION__);
- DBG_SET_LOG("end");
-#endif // FAST_PICTURESET
-}
-
-#ifdef FAST_PICTURESET
-#else
-
-void PictureSet::setDrawTimes(const PictureSet& src)
-{
- validate(__FUNCTION__);
- if (mWidth != src.mWidth || mHeight != src.mHeight)
- return;
- Pictures* last = mPictures.end();
- Pictures* working = mPictures.begin();
- if (working == last)
- return;
- const Pictures* srcLast = src.mPictures.end();
- const Pictures* srcWorking = src.mPictures.begin();
- for (; srcWorking != srcLast; srcWorking++) {
- if (srcWorking->mWroteElapsed == false)
- continue;
- while ((srcWorking->mArea != working->mArea ||
- srcWorking->mPicture != working->mPicture)) {
- if (++working == last)
- return;
- }
- DBG_SET_LOGD("%p [%d] [%d] {%d,%d,r=%d,b=%d} working->mElapsed=%d <- %d",
- this, working - mPictures.begin(), srcWorking - src.mPictures.begin(),
- working->mArea.fLeft, working->mArea.fTop,
- working->mArea.fRight, working->mArea.fBottom,
- working->mElapsed, srcWorking->mElapsed);
- working->mElapsed = srcWorking->mElapsed;
- }
-}
-
-void PictureSet::setPicture(size_t i, SkPicture* p)
-{
- SkSafeUnref(mPictures[i].mPicture);
- mPictures[i].mPicture = p;
- mPictures[i].mEmpty = emptyPicture(p);
-}
-
-#ifdef CONTEXT_RECORDING
-void PictureSet::setGraphicsOperationCollection(size_t i, WebCore::GraphicsOperationCollection* p)
-{
- SkSafeUnref(mPictures[i].mGraphicsOperationCollection);
- mPictures[i].mGraphicsOperationCollection = p;
-}
-#endif
-
-void PictureSet::split(PictureSet* out) const
-{
- dump(__FUNCTION__);
- DBG_SET_LOGD("%p", this);
- SkIRect totalBounds;
- out->mWidth = mWidth;
- out->mHeight = mHeight;
- totalBounds.set(0, 0, mWidth, mHeight);
- SkRegion* total = new SkRegion(totalBounds);
- const Pictures* last = mPictures.end();
- const Pictures* working;
- uint32_t balance = 0;
- int multiUnsplitFastPictures = 0; // > 1 has more than 1
- for (working = mPictures.begin(); working != last; working++) {
- if (working->mElapsed >= MAX_DRAW_TIME || working->mSplit)
- continue;
- if (++multiUnsplitFastPictures > 1)
- break;
- }
- for (working = mPictures.begin(); working != last; working++) {
- uint32_t elapsed = working->mElapsed;
- if (elapsed < MAX_DRAW_TIME) {
- bool split = working->mSplit;
- DBG_SET_LOGD("elapsed=%d working=%p total->getBounds()="
- "{%d,%d,r=%d,b=%d} split=%s", elapsed, working,
- total->getBounds().fLeft, total->getBounds().fTop,
- total->getBounds().fRight, total->getBounds().fBottom,
- split ? "true" : "false");
- if (multiUnsplitFastPictures <= 1 || split) {
- total->op(working->mArea, SkRegion::kDifference_Op);
- out->add(working->mArea, elapsed, split,
- working->mEmpty);
- } else if (balance < elapsed)
- balance = elapsed;
- continue;
- }
- total->op(working->mArea, SkRegion::kDifference_Op);
- const SkIRect& bounds = working->mArea;
- int width = bounds.width();
- int height = bounds.height();
- int across = 1;
- int down = 1;
- while (height >= MIN_SPLITTABLE || width >= MIN_SPLITTABLE) {
- if (height >= width) {
- height >>= 1;
- down <<= 1;
- } else {
- width >>= 1;
- across <<= 1 ;
- }
- if ((elapsed >>= 1) < MAX_DRAW_TIME)
- break;
- }
- width = bounds.width();
- height = bounds.height();
- int top = bounds.fTop;
- for (int indexY = 0; indexY < down; ) {
- int bottom = bounds.fTop + height * ++indexY / down;
- int left = bounds.fLeft;
- for (int indexX = 0; indexX < across; ) {
- int right = bounds.fLeft + width * ++indexX / across;
- SkIRect cBounds;
- cBounds.set(left, top, right, bottom);
- out->add(cBounds, elapsed, true,
- (across | down) != 1 ? false : working->mEmpty);
- left = right;
- }
- top = bottom;
- }
- }
- DBG_SET_LOGD("%p w=%d h=%d total->isEmpty()=%s multiUnsplitFastPictures=%d",
- this, mWidth, mHeight, total->isEmpty() ? "true" : "false",
- multiUnsplitFastPictures);
- if (!total->isEmpty() && multiUnsplitFastPictures > 1)
- out->add(*total, balance, false);
- delete total;
- validate(__FUNCTION__);
- out->dump("split-out");
-}
-
-#endif // FAST_PICTURESET
-
-bool PictureSet::validate(const char* funct) const
-{
-#ifdef FAST_PICTURESET
- return true;
-#else
- bool valid = true;
-#if PICTURE_SET_VALIDATE
- SkRegion all;
- const Pictures* first = mPictures.begin();
- for (const Pictures* working = mPictures.end(); working != first; ) {
- --working;
- const SkPicture* pict = working->mPicture;
- const SkRegion& area = working->mArea;
- const SkIRect& bounds = area.getBounds();
- bool localValid = false;
- if (working->mUnsplit.isEmpty())
- ALOGD("%s working->mUnsplit.isEmpty()", funct);
- else if (working->mUnsplit.contains(bounds) == false)
- ALOGD("%s working->mUnsplit.contains(bounds) == false", funct);
- else if (working->mElapsed >= 1000)
- ALOGD("%s working->mElapsed >= 1000", funct);
- else if ((working->mSplit & 0xfe) != 0)
- ALOGD("%s (working->mSplit & 0xfe) != 0", funct);
- else if ((working->mWroteElapsed & 0xfe) != 0)
- ALOGD("%s (working->mWroteElapsed & 0xfe) != 0", funct);
- else if (pict != NULL) {
- int pictWidth = pict->width();
- int pictHeight = pict->height();
- if (pictWidth < bounds.width())
- ALOGD("%s pictWidth=%d < bounds.width()=%d", funct, pictWidth, bounds.width());
- else if (pictHeight < bounds.height())
- ALOGD("%s pictHeight=%d < bounds.height()=%d", funct, pictHeight, bounds.height());
- else if (working->mArea.isEmpty())
- ALOGD("%s working->mArea.isEmpty()", funct);
- else
- localValid = true;
- } else
- localValid = true;
- working->mArea.validate();
- if (localValid == false) {
- if (all.contains(area) == true)
- ALOGD("%s all.contains(area) == true", funct);
- else
- localValid = true;
- }
- valid &= localValid;
- all.op(area, SkRegion::kUnion_Op);
- }
- const SkIRect& allBounds = all.getBounds();
- if (valid) {
- valid = false;
- if (allBounds.width() != mWidth)
- ALOGD("%s allBounds.width()=%d != mWidth=%d", funct, allBounds.width(), mWidth);
- else if (allBounds.height() != mHeight)
- ALOGD("%s allBounds.height()=%d != mHeight=%d", funct, allBounds.height(), mHeight);
- else
- valid = true;
- }
- while (valid == false)
- ;
-#endif
- return valid;
-#endif // FAST_PICTURESET
-}
-
-} /* namespace android */
diff --git a/Source/WebKit/android/jni/PictureSet.h b/Source/WebKit/android/jni/PictureSet.h
deleted file mode 100644
index 1e639da..0000000
--- a/Source/WebKit/android/jni/PictureSet.h
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright 2008, 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 PictureSet_h
-#define PictureSet_h
-
-#define PICTURE_SET_DUMP 0
-#define PICTURE_SET_DEBUG 0
-#define PICTURE_SET_VALIDATE 0
-
-#if PICTURE_SET_DEBUG
-#define DBG_SET_LOG(message) ALOGD("%s %s", __FUNCTION__, message)
-#define DBG_SET_LOGD(format, ...) ALOGD("%s " format, __FUNCTION__, __VA_ARGS__)
-#define DEBUG_SET_UI_LOGD(...) ALOGD(__VA_ARGS__)
-#else
-#define DBG_SET_LOG(message) ((void)0)
-#define DBG_SET_LOGD(format, ...) ((void)0)
-#define DEBUG_SET_UI_LOGD(...) ((void)0)
-#endif
-
-#include "jni.h"
-#include "SkRegion.h"
-#include <wtf/Vector.h>
-#include <wtf/HashMap.h>
-
-#include "GraphicsOperationCollection.h"
-
-// #define FAST_PICTURESET // use a hierarchy of pictures
-// #define CONTEXT_RECORDING // use the new PlatformGraphicsContextRecording
-
-class SkCanvas;
-class SkPicture;
-class SkIRect;
-
-namespace android {
-
-#ifdef FAST_PICTURESET
- struct BucketPicture {
- SkPicture* mPicture;
- SkIRect mArea;
- SkIRect mRealArea;
- bool mBase;
- };
-
- typedef std::pair<int, int> BucketPosition;
- typedef WTF::Vector<BucketPicture> Bucket;
- typedef WTF::HashMap<BucketPosition , Bucket* > BucketMap;
-#endif
-
- class PictureSet {
- public:
- PictureSet();
- PictureSet(const PictureSet& src) { set(src); }
- PictureSet(SkPicture* picture);
- virtual ~PictureSet();
-
-#ifdef FAST_PICTURESET
- void displayBucket(Bucket* bucket);
- void displayBuckets();
- WTF::Vector<Bucket*>* bucketsToUpdate() { return &mUpdatedBuckets; }
- Bucket* getBucket(int x, int y);
- void addToBucket(Bucket* bucket, int dx, int dy, SkIRect& rect);
- void gatherBucketsForArea(WTF::Vector<Bucket*>& list, const SkIRect& rect);
- void splitAdd(const SkIRect& rect);
-#endif
-
- void add(const SkRegion& area, uint32_t elapsed, bool split);
-
- // Update mWidth/mHeight, and adds any additional inval region
- void setDimensions(int width, int height, SkRegion* inval = 0);
- void clear();
- bool draw(SkCanvas* );
- static PictureSet* GetNativePictureSet(JNIEnv* env, jobject jpic);
- int height() const { return mHeight; }
- bool isEmpty() const; // returns true if empty or only trivial content
- void set(const PictureSet& );
-
-#ifdef FAST_PICTURESET
-#else
- void add(const SkIRect& area, uint32_t elapsed, bool split, bool empty);
- const SkIRect& bounds(size_t i) const {
- return mPictures[i].mArea; }
- void setPicture(size_t i, SkPicture* p);
-#ifdef CONTEXT_RECORDING
- void setGraphicsOperationCollection(size_t i, WebCore::GraphicsOperationCollection* p);
-#endif
- void setDrawTimes(const PictureSet& );
- size_t size() const { return mPictures.size(); }
- void split(PictureSet* result) const;
- bool upToDate(size_t i) const { return mPictures[i].mPicture != NULL; }
-#endif
- int width() const { return mWidth; }
- void dump(const char* label) const;
- bool validate(const char* label) const;
- private:
- bool emptyPicture(SkPicture* ) const; // true if no text, images, paths
-
-#ifdef FAST_PICTURESET
- BucketMap mBuckets;
- WTF::Vector<Bucket*> mUpdatedBuckets;
- int mBucketSizeX;
- int mBucketSizeY;
- int mBucketCountX;
- int mBucketCountY;
-#else
-
- struct Pictures {
- SkIRect mArea;
- SkPicture* mPicture;
-#ifdef CONTEXT_RECORDING
- WebCore::GraphicsOperationCollection* mGraphicsOperationCollection;
-#endif
- SkIRect mUnsplit;
- uint32_t mElapsed;
- bool mSplit : 8;
- bool mWroteElapsed : 8;
- bool mBase : 8; // true if nothing is drawn underneath this
- bool mEmpty : 8; // true if the picture only draws white
- };
- void add(const Pictures* temp);
- WTF::Vector<Pictures> mPictures;
-#endif
- float mBaseArea;
- float mAdditionalArea;
- int mHeight;
- int mWidth;
- };
-}
-
-#endif
diff --git a/Source/WebKit/android/jni/ViewStateSerializer.cpp b/Source/WebKit/android/jni/ViewStateSerializer.cpp
index 5f2480a..02ddca6 100644
--- a/Source/WebKit/android/jni/ViewStateSerializer.cpp
+++ b/Source/WebKit/android/jni/ViewStateSerializer.cpp
@@ -38,7 +38,6 @@
#include "LayerAndroid.h"
#include "LayerContent.h"
#include "PictureLayerContent.h"
-#include "PictureSet.h"
#include "ScrollableLayerAndroid.h"
#include "SkFlattenable.h"
#include "SkPicture.h"
diff --git a/Source/WebKit/android/jni/WebCoreViewBridge.h b/Source/WebKit/android/jni/WebCoreViewBridge.h
index b04a0f9..cca4ca5 100644
--- a/Source/WebKit/android/jni/WebCoreViewBridge.h
+++ b/Source/WebKit/android/jni/WebCoreViewBridge.h
@@ -48,7 +48,7 @@ public:
virtual ~WebCoreViewBridge() { }
- virtual void draw(WebCore::GraphicsContext* ctx,
+ virtual void draw(WebCore::GraphicsContext* ctx,
const WebCore::IntRect& rect) = 0;
const WebCore::IntRect& getBounds() const
diff --git a/Source/WebKit/android/jni/WebViewCore.cpp b/Source/WebKit/android/jni/WebViewCore.cpp
index e0379a8..4e6ffc6 100644
--- a/Source/WebKit/android/jni/WebViewCore.cpp
+++ b/Source/WebKit/android/jni/WebViewCore.cpp
@@ -89,7 +89,7 @@
#include "Page.h"
#include "PageGroup.h"
#include "PictureLayerContent.h"
-#include "PictureSetLayerContent.h"
+#include "PicturePileLayerContent.h"
#include "PlatformKeyboardEvent.h"
#include "PlatformString.h"
#include "PluginWidgetAndroid.h"
@@ -169,17 +169,6 @@ FILE* gRenderTreeFile = 0;
#include "RenderLayerCompositor.h"
#endif
-// In some cases, too many invalidations passed to the UI will slow us down.
-// Limit ourselves to 32 rectangles, past this just send the area bounds to the UI.
-// see WebViewCore::recordPictureSet().
-#define MAX_INVALIDATIONS 32
-
-/* We pass this flag when recording the actual content, so that we don't spend
- time actually regionizing complex path clips, when all we really want to do
- is record them.
- */
-#define PICT_RECORD_FLAGS SkPicture::kUsePathBoundsForClip_RecordingFlag
-
////////////////////////////////////////////////////////////////////////////////////////////////
namespace android {
@@ -430,7 +419,6 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m
, m_scrollOffsetX(0)
, m_scrollOffsetY(0)
, m_mousePos(WebCore::IntPoint(0,0))
- , m_progressDone(false)
, m_screenWidth(320)
, m_screenHeight(240)
, m_textWrapWidth(320)
@@ -610,18 +598,8 @@ static bool layoutIfNeededRecursive(WebCore::Frame* f)
WebCore::FrameView* v = f->view();
if (!v)
return true;
-
- if (v->needsLayout())
- v->layout(f->tree()->parent());
-
- WebCore::Frame* child = f->tree()->firstChild();
- bool success = true;
- while (child) {
- success &= layoutIfNeededRecursive(child);
- child = child->tree()->nextSibling();
- }
-
- return success && !v->needsLayout();
+ v->updateLayoutAndStyleIfNeededRecursive();
+ return !v->needsLayout();
}
WebCore::Node* WebViewCore::currentFocus()
@@ -629,19 +607,16 @@ WebCore::Node* WebViewCore::currentFocus()
return focusedFrame()->document()->focusedNode();
}
-void WebViewCore::recordPictureSet(PictureSet* content)
+void WebViewCore::recordPicturePile()
{
TRACE_METHOD();
// if there is no document yet, just return
if (!m_mainFrame->document()) {
- DBG_SET_LOG("!m_mainFrame->document()");
- return;
- }
- if (m_addInval.isEmpty()) {
- DBG_SET_LOG("m_addInval.isEmpty()");
+ ALOGV("!m_mainFrame->document()");
return;
}
+
// Call layout to ensure that the contentWidth and contentHeight are correct
// it's fine for layout to gather invalidates, but defeat sending a message
// back to java to call webkitDraw, since we're already in the middle of
@@ -704,6 +679,8 @@ void WebViewCore::recordPictureSet(PictureSet* content)
// If the new total is larger than the content, resize the view to include
// all the content.
if (!contentRect.contains(total)) {
+ // TODO: Does this ever happen? Is this needed now that we don't flatten
+ // frames?
// Resize the view to change the overflow clip.
view->resize(total.fRight, total.fBottom);
@@ -723,51 +700,15 @@ void WebViewCore::recordPictureSet(PictureSet* content)
height = view->contentsHeight();
}
-#if USE(ACCELERATED_COMPOSITING)
- // The invals are not always correct when the content size has changed. For
- // now, let's just reset the inval so that it invalidates the entire content
- // -- the pictureset will be fully repainted, tiles will be marked dirty and
- // will have to be repainted.
-
- // FIXME: the webkit invals ought to have been enough...
- if (content->width() != width || content->height() != height) {
- SkIRect r;
- r.fLeft = 0;
- r.fTop = 0;
- r.fRight = width;
- r.fBottom = height;
- m_addInval.setRect(r);
- }
-#endif
-
- content->setDimensions(width, height, &m_addInval);
+ m_content.setSize(IntSize(width, height));
- // Add the current inval rects to the PictureSet, and rebuild it.
- content->add(m_addInval, 0, false);
-
- // If we have too many invalidations, just get the area bounds
- SkRegion::Iterator iterator(m_addInval);
- int nbInvals = 0;
- while (!iterator.done()) {
- iterator.next();
- nbInvals++;
- if (nbInvals > MAX_INVALIDATIONS)
- break;
- }
- if (nbInvals > MAX_INVALIDATIONS) {
- SkIRect r = m_addInval.getBounds();
- m_addInval.setRect(r);
- }
// Rebuild the pictureset (webkit repaint)
- rebuildPictureSet(content);
+ m_content.updatePicturesIfNeeded(this);
}
void WebViewCore::clearContent()
{
- DBG_SET_LOG("");
- m_content.clear();
- m_addInval.setEmpty();
- m_rebuildInval.setEmpty();
+ m_content.reset();
updateLocale();
}
@@ -778,86 +719,51 @@ bool WebViewCore::focusBoundsChanged()
return result;
}
-SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval)
+void WebViewCore::paintContents(WebCore::GraphicsContext* gc, WebCore::IntRect& dirty)
{
WebCore::FrameView* view = m_mainFrame->view();
- int width = view->contentsWidth();
- int height = view->contentsHeight();
- SkPicture* picture = new SkPicture();
- SkAutoPictureRecord arp(picture, width, height, PICT_RECORD_FLAGS);
- SkAutoMemoryUsageProbe mup(__FUNCTION__);
- SkCanvas* recordingCanvas = arp.getRecordingCanvas();
- WebCore::PlatformGraphicsContextSkia pgc(recordingCanvas);
- WebCore::GraphicsContext gc(&pgc);
IntPoint origin = view->minimumScrollPosition();
- WebCore::IntRect drawArea(inval.fLeft + origin.x(), inval.fTop + origin.y(),
- inval.width(), inval.height());
- recordingCanvas->translate(-drawArea.x(), -drawArea.y());
- recordingCanvas->save();
- view->platformWidget()->draw(&gc, drawArea);
- m_rebuildInval.op(inval, SkRegion::kUnion_Op);
- DBG_SET_LOGD("m_rebuildInval={%d,%d,r=%d,b=%d}",
- m_rebuildInval.getBounds().fLeft, m_rebuildInval.getBounds().fTop,
- m_rebuildInval.getBounds().fRight, m_rebuildInval.getBounds().fBottom);
-
- return picture;
+ IntRect drawArea = dirty;
+ gc->translate(-origin.x(), -origin.y());
+ drawArea.move(origin.x(), origin.y());
+ view->platformWidget()->draw(gc, drawArea);
}
-#ifdef CONTEXT_RECORDING
-GraphicsOperationCollection* WebViewCore::rebuildGraphicsOperationCollection(const SkIRect& inval)
+SkCanvas* WebViewCore::createPrerenderCanvas(PrerenderedInval* prerendered)
{
- WebCore::FrameView* view = m_mainFrame->view();
- int width = view->contentsWidth();
- int height = view->contentsHeight();
-
- IntPoint origin = view->minimumScrollPosition();
- WebCore::IntRect drawArea(inval.fLeft + origin.x(), inval.fTop + origin.y(),
- inval.width(), inval.height());
-
- AutoGraphicsOperationCollection autoPicture(drawArea);
- view->platformWidget()->draw(autoPicture.context(), drawArea);
-
- m_rebuildInval.op(inval, SkRegion::kUnion_Op);
-
- SkSafeRef(autoPicture.picture());
- return autoPicture.picture();
-}
-#endif
-
-void WebViewCore::rebuildPictureSet(PictureSet* pictureSet)
-{
-#ifdef FAST_PICTURESET
- WTF::Vector<Bucket*>* buckets = pictureSet->bucketsToUpdate();
-
- for (unsigned int i = 0; i < buckets->size(); i++) {
- Bucket* bucket = (*buckets)[i];
- for (unsigned int j = 0; j < bucket->size(); j++) {
- BucketPicture& bucketPicture = (*bucket)[j];
- const SkIRect& inval = bucketPicture.mRealArea;
- SkPicture* picture = rebuildPicture(inval);
- SkSafeUnref(bucketPicture.mPicture);
- bucketPicture.mPicture = picture;
- }
- }
- buckets->clear();
-#else
- size_t size = pictureSet->size();
- for (size_t index = 0; index < size; index++) {
- if (pictureSet->upToDate(index))
- continue;
- const SkIRect& inval = pictureSet->bounds(index);
- DBG_SET_LOGD("pictSet=%p [%d] {%d,%d,w=%d,h=%d}", pictureSet, index,
- inval.fLeft, inval.fTop, inval.width(), inval.height());
- pictureSet->setPicture(index, rebuildPicture(inval));
-#ifdef CONTEXT_RECORDING
- pictureSet->setGraphicsOperationCollection(index,
- rebuildGraphicsOperationCollection(inval));
-#endif
+ IntRect screen(m_scrollOffsetX, m_scrollOffsetY, m_screenWidth, m_screenHeight);
+ if (prerendered->area.isEmpty() || !prerendered->area.intersects(screen))
+ return 0;
+ FloatRect scaledArea = prerendered->area;
+ scaledArea.scale(m_scale);
+ IntRect enclosingScaledArea = enclosingIntRect(scaledArea);
+ if (enclosingScaledArea.isEmpty())
+ return 0;
+ prerendered->screenArea = enclosingScaledArea;
+ FloatRect enclosingDocArea(enclosingScaledArea);
+ enclosingDocArea.scale(1 / m_scale);
+ prerendered->area = enclosingIntRect(enclosingDocArea);
+ if (prerendered->area.isEmpty())
+ return 0;
+ // TODO: We need a better heuristic for this. We should change this to:
+ // 1) Limit by area, not width/height (as we care more about the RAM than size)
+ // 2) Clip by the screen, but "round out" to make sure we cover partially
+ // visible tiles
+ int maxWidth = ceilf(m_screenWidth * m_scale);
+ int maxHeight = ceilf(m_screenHeight * m_scale);
+ if (enclosingScaledArea.width() <= maxWidth
+ && enclosingScaledArea.height() <= maxHeight) {
+ prerendered->bitmap.setConfig(SkBitmap::kARGB_8888_Config,
+ enclosingScaledArea.width(),
+ enclosingScaledArea.height());
+ prerendered->bitmap.allocPixels();
+ SkCanvas* bitmapCanvas = new SkCanvas(prerendered->bitmap);
+ bitmapCanvas->scale(m_scale, m_scale);
+ bitmapCanvas->translate(-enclosingDocArea.x(), -enclosingDocArea.y());
+ return bitmapCanvas;
}
-
- pictureSet->validate(__FUNCTION__);
-#endif
+ return 0;
}
void WebViewCore::notifyAnimationStarted()
@@ -896,7 +802,8 @@ BaseLayerAndroid* WebViewCore::createBaseLayer()
bodyHasFixedBackgroundImage = style->hasFixedBackgroundImage();
}
- PictureSetLayerContent* content = new PictureSetLayerContent(m_content);
+ PicturePileLayerContent* content = new PicturePileLayerContent(m_content);
+ m_content.clearPrerenders();
BaseLayerAndroid* realBase = 0;
LayerAndroid* base = 0;
@@ -952,46 +859,22 @@ BaseLayerAndroid* WebViewCore::createBaseLayer()
BaseLayerAndroid* WebViewCore::recordContent(SkIPoint* point)
{
- // If there is a pending style recalculation, just return.
- if (m_mainFrame->document()->isPendingStyleRecalc()) {
- DBG_SET_LOG("recordContent: pending style recalc, ignoring.");
- return 0;
- }
- float progress = (float) m_mainFrame->page()->progress()->estimatedProgress();
- m_progressDone = progress <= 0.0f || progress >= 1.0f;
- recordPictureSet(&m_content);
- if (!m_progressDone && m_content.isEmpty()) {
- DBG_SET_LOGD("empty (progress=%g)", progress);
- return 0;
- }
+ recordPicturePile();
BaseLayerAndroid* baseLayer = createBaseLayer();
- baseLayer->markAsDirty(m_addInval);
- m_addInval.setEmpty();
+ baseLayer->markAsDirty(m_content.dirtyRegion());
+ m_content.dirtyRegion().setEmpty();
#if USE(ACCELERATED_COMPOSITING)
#else
baseLayer->markAsDirty(m_rebuildInval);
#endif
- m_rebuildInval.setEmpty();
- point->fX = m_content.width();
- point->fY = m_content.height();
+ point->fX = m_content.size().width();
+ point->fY = m_content.size().height();
return baseLayer;
}
-void WebViewCore::splitContent(PictureSet* content)
-{
-#ifdef FAST_PICTURESET
-#else
- bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame);
- ALOG_ASSERT(layoutSucceeded, "Can never be called recursively");
- content->split(&m_content);
- rebuildPictureSet(&m_content);
- content->set(m_content);
-#endif // FAST_PICTURESET
-}
-
void WebViewCore::scrollTo(int x, int y, bool animate)
{
ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
@@ -1041,14 +924,10 @@ void WebViewCore::contentDraw()
void WebViewCore::contentInvalidate(const WebCore::IntRect &r)
{
- DBG_SET_LOGD("rect={%d,%d,w=%d,h=%d}", r.x(), r.y(), r.width(), r.height());
- SkIRect rect(r);
- if (!rect.intersect(0, 0, INT_MAX, INT_MAX))
- return;
- m_addInval.op(rect, SkRegion::kUnion_Op);
- DBG_SET_LOGD("m_addInval={%d,%d,r=%d,b=%d}",
- m_addInval.getBounds().fLeft, m_addInval.getBounds().fTop,
- m_addInval.getBounds().fRight, m_addInval.getBounds().fBottom);
+ IntPoint origin = m_mainFrame->view()->minimumScrollPosition();
+ IntRect dirty = r;
+ dirty.move(-origin.x(), -origin.y());
+ m_content.invalidate(dirty);
if (!m_skipContentDraw)
contentDraw();
}
@@ -4560,13 +4439,6 @@ static jint RecordContent(JNIEnv* env, jobject obj, jint nativeClass, jobject pt
return reinterpret_cast<jint>(result);
}
-static void SplitContent(JNIEnv* env, jobject obj, jint nativeClass,
- jint content)
-{
- WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
- viewImpl->splitContent(reinterpret_cast<PictureSet*>(content));
-}
-
static void SendListBoxChoice(JNIEnv* env, jobject obj, jint nativeClass,
jint choice)
{
@@ -5074,8 +4946,6 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = {
(void*) RecordContent },
{ "setViewportSettingsFromNative", "(I)V",
(void*) SetViewportSettingsFromNative },
- { "nativeSplitContent", "(II)V",
- (void*) SplitContent },
{ "nativeSetBackgroundColor", "(II)V",
(void*) SetBackgroundColor },
{ "nativeRegisterURLSchemeAsLocal", "(ILjava/lang/String;)V",
diff --git a/Source/WebKit/android/jni/WebViewCore.h b/Source/WebKit/android/jni/WebViewCore.h
index 3e1dbab..8dc1d07 100644
--- a/Source/WebKit/android/jni/WebViewCore.h
+++ b/Source/WebKit/android/jni/WebViewCore.h
@@ -31,7 +31,7 @@
#include "FileChooser.h"
#include "FocusDirection.h"
#include "HitTestResult.h"
-#include "PictureSet.h"
+#include "PicturePile.h"
#include "PlatformGraphicsContext.h"
#include "Position.h"
#include "ScrollTypes.h"
@@ -121,7 +121,7 @@ namespace android {
};
// one instance of WebViewCore per page for calling into Java's WebViewCore
- class WebViewCore : public WebCoreRefObject {
+ class WebViewCore : public WebCoreRefObject, public WebCore::PicturePainter {
public:
/**
* Initialize the native WebViewCore with a JNI environment, a Java
@@ -526,9 +526,6 @@ namespace android {
WebCore::Frame* mainFrame() const { return m_mainFrame; }
WebCore::Frame* focusedFrame() const;
- // utility to split slow parts of the picture set
- void splitContent(PictureSet*);
-
void notifyWebAppCanBeInstalled();
void deleteText(int startX, int startY, int endX, int endY);
@@ -625,13 +622,13 @@ namespace android {
WebCore::Node* currentFocus();
// Create a set of pictures to represent the drawn DOM, driven by
// the invalidated region and the time required to draw (used to draw)
- void recordPictureSet(PictureSet* master);
+ void recordPicturePile();
- SkPicture* rebuildPicture(const SkIRect& inval);
+ virtual void paintContents(WebCore::GraphicsContext* gc, WebCore::IntRect& dirty);
+ virtual SkCanvas* createPrerenderCanvas(WebCore::PrerenderedInval* prerendered);
#ifdef CONTEXT_RECORDING
WebCore::GraphicsOperationCollection* rebuildGraphicsOperationCollection(const SkIRect& inval);
#endif
- void rebuildPictureSet(PictureSet* );
void sendNotifyProgressFinished();
/*
* Handle a mouse click, either from a touch or trackball press.
@@ -750,9 +747,7 @@ namespace android {
struct TextFieldInitDataGlue* m_textFieldInitDataGlue;
WebCore::Frame* m_mainFrame;
WebCoreReply* m_popupReply;
- PictureSet m_content; // the set of pictures to draw
- SkRegion m_addInval; // the accumulated inval region (not yet drawn)
- SkRegion m_rebuildInval; // the accumulated region for rebuilt pictures
+ WebCore::PicturePile m_content; // the set of pictures to draw
// Used in passToJS to avoid updating the UI text field until after the
// key event has been processed.
bool m_blockTextfieldUpdates;
@@ -766,7 +761,6 @@ namespace android {
int m_scrollOffsetX; // webview.java's current scroll in X
int m_scrollOffsetY; // webview.java's current scroll in Y
WebCore::IntPoint m_mousePos;
- bool m_progressDone;
int m_screenWidth; // width of the visible rect in document coordinates
int m_screenHeight;// height of the visible rect in document coordinates
int m_textWrapWidth;
diff --git a/Source/WebKit/android/nav/WebView.cpp b/Source/WebKit/android/nav/WebView.cpp
index 51ffdfe..9d4d7a4 100644
--- a/Source/WebKit/android/nav/WebView.cpp
+++ b/Source/WebKit/android/nav/WebView.cpp
@@ -293,12 +293,11 @@ int drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect,
return 0;
}
-PictureSet* draw(SkCanvas* canvas, SkColor bgColor, DrawExtras extras, bool split)
+void draw(SkCanvas* canvas, SkColor bgColor, DrawExtras extras)
{
- PictureSet* ret = 0;
if (!m_baseLayer) {
canvas->drawColor(bgColor);
- return ret;
+ return;
}
// draw the content of the base layer first
@@ -327,8 +326,6 @@ PictureSet* draw(SkCanvas* canvas, SkColor bgColor, DrawExtras extras, bool spli
m_baseLayer->setMatrix(canvas->getTotalMatrix());
canvas->resetMatrix();
m_baseLayer->draw(canvas, getDrawExtra(extras));
-
- return ret;
}
int getScaledMaxXScroll()
@@ -543,14 +540,6 @@ bool setBaseLayer(BaseLayerAndroid* newBaseLayer, bool showVisualIndicator,
return queueFull;
}
-void replaceBaseContent(PictureSet* set)
-{
- if (!m_baseLayer)
- return;
- // TODO: remove the split picture codepath
- delete set;
-}
-
void copyBaseContentToPicture(SkPicture* picture)
{
if (!m_baseLayer)
@@ -805,16 +794,14 @@ static SkRect jrectf_to_rect(JNIEnv* env, jobject obj)
return rect;
}
-static jint nativeDraw(JNIEnv *env, jobject obj, jobject canv,
+static void nativeDraw(JNIEnv *env, jobject obj, jobject canv,
jobject visible, jint color,
- jint extras, jboolean split) {
+ jint extras) {
SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
WebView* webView = GET_NATIVE_VIEW(env, obj);
SkRect visibleRect = jrectf_to_rect(env, visible);
webView->setVisibleRect(visibleRect);
- PictureSet* pictureSet = webView->draw(canvas, color,
- static_cast<WebView::DrawExtras>(extras), split);
- return reinterpret_cast<jint>(pictureSet);
+ webView->draw(canvas, color, static_cast<WebView::DrawExtras>(extras));
}
static jint nativeCreateDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView,
@@ -898,12 +885,6 @@ static BaseLayerAndroid* nativeGetBaseLayer(JNIEnv *env, jobject obj)
return GET_NATIVE_VIEW(env, obj)->getBaseLayer();
}
-static void nativeReplaceBaseContent(JNIEnv *env, jobject obj, jint content)
-{
- PictureSet* set = reinterpret_cast<PictureSet*>(content);
- GET_NATIVE_VIEW(env, obj)->replaceBaseContent(set);
-}
-
static void nativeCopyBaseContentToPicture(JNIEnv *env, jobject obj, jobject pict)
{
SkPicture* picture = GraphicsJNI::getNativePicture(env, pict);
@@ -1110,7 +1091,7 @@ static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl)
SkDumpCanvas canvas(&dumper);
// this will playback the picture into the canvas, which will
// spew its contents to the dumper
- view->draw(&canvas, 0, WebView::DrawExtrasNone, false);
+ view->draw(&canvas, 0, WebView::DrawExtrasNone);
// we're done with the file now
fwrite("\n", 1, 1, file);
fclose(file);
@@ -1249,7 +1230,7 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeCreate },
{ "nativeDestroy", "()V",
(void*) nativeDestroy },
- { "nativeDraw", "(Landroid/graphics/Canvas;Landroid/graphics/RectF;IIZ)I",
+ { "nativeDraw", "(Landroid/graphics/Canvas;Landroid/graphics/RectF;II)V",
(void*) nativeDraw },
{ "nativeCreateDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;FI)I",
(void*) nativeCreateDrawGLFunction },
@@ -1271,8 +1252,6 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeSetBaseLayer },
{ "nativeGetBaseLayer", "()I",
(void*) nativeGetBaseLayer },
- { "nativeReplaceBaseContent", "(I)V",
- (void*) nativeReplaceBaseContent },
{ "nativeCopyBaseContentToPicture", "(Landroid/graphics/Picture;)V",
(void*) nativeCopyBaseContentToPicture },
{ "nativeHasContent", "()Z",