summaryrefslogtreecommitdiffstats
path: root/Source/WebKit/android
diff options
context:
space:
mode:
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",