diff options
Diffstat (limited to 'Source/WebKit')
-rw-r--r-- | Source/WebKit/Android.mk | 2 | ||||
-rw-r--r-- | Source/WebKit/android/AndroidLog.h | 7 | ||||
-rw-r--r-- | Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp | 4 | ||||
-rw-r--r-- | Source/WebKit/android/jni/PicturePile.cpp | 299 | ||||
-rw-r--r-- | Source/WebKit/android/jni/PicturePile.h | 121 | ||||
-rw-r--r-- | Source/WebKit/android/jni/PictureSet.cpp | 1244 | ||||
-rw-r--r-- | Source/WebKit/android/jni/PictureSet.h | 152 | ||||
-rw-r--r-- | Source/WebKit/android/jni/ViewStateSerializer.cpp | 1 | ||||
-rw-r--r-- | Source/WebKit/android/jni/WebCoreViewBridge.h | 2 | ||||
-rw-r--r-- | Source/WebKit/android/jni/WebViewCore.cpp | 260 | ||||
-rw-r--r-- | Source/WebKit/android/jni/WebViewCore.h | 18 | ||||
-rw-r--r-- | Source/WebKit/android/nav/WebView.cpp | 212 |
12 files changed, 610 insertions, 1712 deletions
diff --git a/Source/WebKit/Android.mk b/Source/WebKit/Android.mk index 67da200..c3e9798 100644 --- a/Source/WebKit/Android.mk +++ b/Source/WebKit/Android.mk @@ -65,7 +65,7 @@ LOCAL_SRC_FILES += \ android/jni/JavaSharedClient.cpp \ android/jni/MIMETypeRegistry.cpp \ android/jni/MockGeolocation.cpp \ - android/jni/PictureSet.cpp \ + android/jni/PicturePile.cpp \ android/jni/WebCoreFrameBridge.cpp \ android/jni/WebCoreJni.cpp \ android/jni/WebFrameView.cpp \ 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/WebCoreSupport/FrameLoaderClientAndroid.cpp b/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp index 271fe58..ac5cd9d 100644 --- a/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp +++ b/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp @@ -422,7 +422,9 @@ void FrameLoaderClientAndroid::dispatchDidFirstLayout() { // so that about:blank will update the screen. if (!m_frame->tree()->parent()) { // Only need to notify Java side for the top frame - WebViewCore::getWebViewCore(m_frame->view())->didFirstLayout(); + WebViewCore* core = WebViewCore::getWebViewCore(m_frame->view()); + if (core) + core->didFirstLayout(); } } diff --git a/Source/WebKit/android/jni/PicturePile.cpp b/Source/WebKit/android/jni/PicturePile.cpp new file mode 100644 index 0000000..f3e46ac --- /dev/null +++ b/Source/WebKit/android/jni/PicturePile.cpp @@ -0,0 +1,299 @@ +/* + * 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->translate(-drawArea.x(), -drawArea.y()); + 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) +{ + 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)) + return inval.get(); + return 0; + } + } + 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..1a1fc16 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" @@ -119,10 +119,12 @@ #include "SkTDArray.h" #include "SkTypes.h" #include "SkCanvas.h" +#include "SkGraphics.h" #include "SkPicture.h" #include "SkUtils.h" #include "Text.h" #include "TextIterator.h" +#include "TilesManager.h" #include "TypingCommand.h" #include "WebCache.h" #include "WebCoreFrameBridge.h" @@ -169,17 +171,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 +421,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) @@ -541,6 +531,9 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m AndroidNetworkLibraryImpl::InitWithApplicationContext(env, 0); + // increase the font cache size beyond the standard system setting + SkGraphics::SetFontCacheLimit(1572864); // 1572864 bytes == 1.5 MB + // Static initialisation of certain important V8 static data gets performed at system startup when // libwebcore gets loaded. We now need to associate the WebCore thread with V8 to complete // initialisation. @@ -610,18 +603,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 +612,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 +684,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 +705,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); - - // Add the current inval rects to the PictureSet, and rebuild it. - content->add(m_addInval, 0, false); + m_content.setSize(IntSize(width, height)); - // 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 +724,55 @@ 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 - } - - pictureSet->validate(__FUNCTION__); -#endif + if (prerendered->area.isEmpty()) + return 0; + FloatRect scaleTemp(m_scrollOffsetX, m_scrollOffsetY, m_screenWidth, m_screenHeight); + scaleTemp.scale(m_scale); + IntRect visibleTileClip = enclosingIntRect(scaleTemp); + FloatRect scaledArea = prerendered->area; + scaledArea.scale(m_scale); + IntRect enclosingScaledArea = enclosingIntRect(scaledArea); + if (enclosingScaledArea.isEmpty()) + return 0; + // "round out" the screen to tile boundaries so that we can clip yet still + // cover any visible tiles with the prerender + int tw = TilesManager::tileWidth(); + int th = TilesManager::tileHeight(); + float left = tw * (int) (visibleTileClip.x() / tw); + float top = th * (int) (visibleTileClip.y() / th); + float right = tw * (int) ceilf(visibleTileClip.maxX() / (float) tw); + float bottom = th * (int) ceilf(visibleTileClip.maxY() / (float) th); + visibleTileClip = IntRect(left, top, right - left, bottom - top); + enclosingScaledArea.intersect(visibleTileClip); + 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; + 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; } void WebViewCore::notifyAnimationStarted() @@ -896,7 +811,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; @@ -917,7 +833,6 @@ BaseLayerAndroid* WebViewCore::createBaseLayer() FixedBackgroundBaseLayerAndroid* baseBackground = new FixedBackgroundBaseLayerAndroid(content); - // TODO -- check we don't have the assumption that baselayer has only one child realBase = new BaseLayerAndroid(0); realBase->setSize(content->width(), content->height()); realBase->addChild(baseBackground); @@ -952,46 +867,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 +932,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 +4447,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 +4954,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 c1d6a88..dae34d8 100644 --- a/Source/WebKit/android/nav/WebView.cpp +++ b/Source/WebKit/android/nav/WebView.cpp @@ -231,29 +231,29 @@ void scrollRectOnScreen(const IntRect& rect) int dx = 0; int left = rect.x(); int right = rect.maxX(); - if (left < m_visibleRect.fLeft) - dx = left - m_visibleRect.fLeft; + if (left < m_visibleContentRect.fLeft) + dx = left - m_visibleContentRect.fLeft; // Only scroll right if the entire width can fit on screen. - else if (right > m_visibleRect.fRight - && right - left < m_visibleRect.width()) - dx = right - m_visibleRect.fRight; + else if (right > m_visibleContentRect.fRight + && right - left < m_visibleContentRect.width()) + dx = right - m_visibleContentRect.fRight; int dy = 0; int top = rect.y(); int bottom = rect.maxY(); - if (top < m_visibleRect.fTop) - dy = top - m_visibleRect.fTop; + if (top < m_visibleContentRect.fTop) + dy = top - m_visibleContentRect.fTop; // Only scroll down if the entire height can fit on screen - else if (bottom > m_visibleRect.fBottom - && bottom - top < m_visibleRect.height()) - dy = bottom - m_visibleRect.fBottom; + else if (bottom > m_visibleContentRect.fBottom + && bottom - top < m_visibleContentRect.height()) + dy = bottom - m_visibleContentRect.fBottom; if ((dx|dy) == 0 || !scrollBy(dx, dy)) return; viewInvalidate(); } -int drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect, - WebCore::IntRect& webViewRect, int titleBarHeight, - WebCore::IntRect& clip, float scale, int extras, bool shouldDraw) +int drawGL(WebCore::IntRect& invScreenRect, WebCore::IntRect* invalRect, + WebCore::IntRect& screenRect, int titleBarHeight, + WebCore::IntRect& screenClip, float scale, int extras, bool shouldDraw) { #if USE(ACCELERATED_COMPOSITING) if (!m_baseLayer) @@ -272,12 +272,12 @@ int drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect, // Make sure we have valid coordinates. We might not have valid coords // if the zoom manager is still initializing. We will be redrawn // once the correct scale is set - if (!m_visibleRect.isFinite()) + if (!m_visibleContentRect.isFinite()) return 0; bool treesSwapped = false; bool newTreeHasAnim = false; - int ret = m_glWebViewState->drawGL(viewRect, m_visibleRect, invalRect, - webViewRect, titleBarHeight, clip, scale, + int ret = m_glWebViewState->drawGL(invScreenRect, m_visibleContentRect, invalRect, + screenRect, titleBarHeight, screenClip, scale, &treesSwapped, &newTreeHasAnim, shouldDraw); if (treesSwapped) { ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); @@ -293,26 +293,31 @@ 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 LayerContent* content = m_baseLayer->content(); int sc = canvas->save(SkCanvas::kClip_SaveFlag); - canvas->clipRect(SkRect::MakeLTRB(0, 0, content->width(), - content->height()), SkRegion::kDifference_Op); + int contentWidth = 0; + int contentHeight = 0; + if (content) { + contentWidth = content->width(); + contentHeight = content->height(); + } + canvas->clipRect(SkRect::MakeLTRB(0, 0, contentWidth, contentHeight), + SkRegion::kDifference_Op); Color c = m_baseLayer->getBackgroundColor(); canvas->drawColor(SkColorSetARGBInline(c.alpha(), c.red(), c.green(), c.blue())); canvas->restoreToCount(sc); // call this to be sure we've adjusted for any scrolling or animations // before we actually draw - m_baseLayer->updateLayerPositions(m_visibleRect); + m_baseLayer->updateLayerPositions(m_visibleContentRect); m_baseLayer->updatePositions(); // We have to set the canvas' matrix on the base layer @@ -321,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() @@ -537,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) @@ -570,8 +565,8 @@ Functor* getFunctor() { return m_glDrawFunctor; } -void setVisibleRect(SkRect& visibleRect) { - m_visibleRect = visibleRect; +void setVisibleContentRect(SkRect& visibleContentRect) { + m_visibleContentRect = visibleContentRect; } void setDrawExtra(DrawExtra *extra, DrawExtras type) @@ -595,7 +590,7 @@ const TransformationMatrix* getLayerTransform(int layerId) { // We need to make sure the drawTransform is up to date as this is // called before a draw() or drawGL() if (layer) { - m_baseLayer->updateLayerPositions(m_visibleRect); + m_baseLayer->updatePositionsRecursive(m_visibleContentRect); return layer->drawTransform(); } } @@ -629,7 +624,7 @@ int getHandleLayerId(SelectText::HandleId handleId, SkIPoint& cursorPoint, void mapLayerRect(int layerId, SkIRect& rect) { const TransformationMatrix* transform = getLayerTransform(layerId); if (transform) - transform->mapRect(rect); + rect = transform->mapRect(rect); } void floatQuadToQuadF(JNIEnv* env, const FloatQuad& nativeTextQuad, @@ -675,7 +670,7 @@ private: // local state for WebView #if USE(ACCELERATED_COMPOSITING) GLWebViewState* m_glWebViewState; #endif - SkRect m_visibleRect; + SkRect m_visibleContentRect; bool m_isHighEndGfx; }; // end of WebView class @@ -690,10 +685,10 @@ class GLDrawFunctor : Functor { GLDrawFunctor(WebView* _wvInstance, int (WebView::*_funcPtr)(WebCore::IntRect&, WebCore::IntRect*, WebCore::IntRect&, int, WebCore::IntRect&, jfloat, jint, bool), - WebCore::IntRect _viewRect, float _scale, int _extras) { + WebCore::IntRect _invScreenRect, float _scale, int _extras) { wvInstance = _wvInstance; funcPtr = _funcPtr; - viewRect = _viewRect; + invScreenRect = _invScreenRect; scale = _scale; extras = _extras; }; @@ -701,39 +696,39 @@ class GLDrawFunctor : Functor { status_t operator()(int messageId, void* data) { TRACE_METHOD(); - if (viewRect.isEmpty()) { + if (invScreenRect.isEmpty()) { // NOOP operation if viewport is empty return 0; } WebCore::IntRect inval; - int titlebarHeight = webViewRect.height() - viewRect.height(); + int titlebarHeight = screenRect.height() - invScreenRect.height(); uirenderer::DrawGlInfo* info = reinterpret_cast<uirenderer::DrawGlInfo*>(data); - WebCore::IntRect clip(info->clipLeft, info->clipTop, - info->clipRight - info->clipLeft, - info->clipBottom - info->clipTop); + WebCore::IntRect screenClip(info->clipLeft, info->clipTop, + info->clipRight - info->clipLeft, + info->clipBottom - info->clipTop); - WebCore::IntRect localViewRect = viewRect; + WebCore::IntRect localInvScreenRect = invScreenRect; if (info->isLayer) { // When webview is on a layer, we need to use the viewport relative - // to the FBO, rather than the screen(which will use viewRect). - localViewRect.setX(clip.x()); - localViewRect.setY(info->height - clip.y() - clip.height()); + // to the FBO, rather than the screen(which will use invScreenRect). + localInvScreenRect.setX(screenClip.x()); + localInvScreenRect.setY(info->height - screenClip.y() - screenClip.height()); } bool shouldDraw = (messageId == uirenderer::DrawGlInfo::kModeDraw); // Send the necessary info to the shader. TilesManager::instance()->shader()->setGLDrawInfo(info); - int returnFlags = (*wvInstance.*funcPtr)(localViewRect, &inval, webViewRect, - titlebarHeight, clip, scale, extras, shouldDraw); + int returnFlags = (*wvInstance.*funcPtr)(localInvScreenRect, &inval, screenRect, + titlebarHeight, screenClip, scale, extras, shouldDraw); if ((returnFlags & uirenderer::DrawGlInfo::kStatusDraw) != 0) { IntRect finalInval; if (inval.isEmpty()) - finalInval = webViewRect; + finalInval = screenRect; else { - finalInval.setX(webViewRect.x() + inval.x()); - finalInval.setY(webViewRect.y() + titlebarHeight + inval.y()); + finalInval.setX(screenRect.x() + inval.x()); + finalInval.setY(screenRect.y() + titlebarHeight + inval.y()); finalInval.setWidth(inval.width()); finalInval.setHeight(inval.height()); } @@ -746,21 +741,24 @@ class GLDrawFunctor : Functor { ALOGV("returnFlags are %d, shouldDraw %d", returnFlags, shouldDraw); return returnFlags; } - void updateRect(WebCore::IntRect& _viewRect) { - viewRect = _viewRect; + void updateScreenRect(WebCore::IntRect& _screenRect) { + screenRect = _screenRect; } - void updateViewRect(WebCore::IntRect& _viewRect) { - webViewRect = _viewRect; + void updateInvScreenRect(WebCore::IntRect& _invScreenRect) { + invScreenRect = _invScreenRect; } void updateScale(float _scale) { scale = _scale; } + void updateExtras(jint _extras) { + extras = _extras; + } private: WebView* wvInstance; int (WebView::*funcPtr)(WebCore::IntRect&, WebCore::IntRect*, WebCore::IntRect&, int, WebCore::IntRect&, float, int, bool); - WebCore::IntRect viewRect; - WebCore::IntRect webViewRect; + WebCore::IntRect invScreenRect; + WebCore::IntRect screenRect; jfloat scale; jint extras; }; @@ -796,33 +794,38 @@ 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); + SkRect visibleContentRect = jrectf_to_rect(env, visible); + webView->setVisibleContentRect(visibleContentRect); + webView->draw(canvas, color, static_cast<WebView::DrawExtras>(extras)); } static jint nativeCreateDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView, - jobject jrect, jobject jviewrect, - jobject jvisiblerect, - jfloat scale, jint extras) { - WebCore::IntRect viewRect = jrect_to_webrect(env, jrect); + jobject jinvscreenrect, jobject jscreenrect, + jobject jvisiblecontentrect, + jfloat scale, jint extras) { + WebCore::IntRect invScreenRect = jrect_to_webrect(env, jinvscreenrect); WebView *wvInstance = (WebView*) nativeView; - SkRect visibleRect = jrectf_to_rect(env, jvisiblerect); - wvInstance->setVisibleRect(visibleRect); - - GLDrawFunctor* functor = new GLDrawFunctor(wvInstance, - &android::WebView::drawGL, viewRect, scale, extras); - wvInstance->setFunctor((Functor*) functor); + SkRect visibleContentRect = jrectf_to_rect(env, jvisiblecontentrect); + wvInstance->setVisibleContentRect(visibleContentRect); + + GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor(); + if (!functor) { + functor = new GLDrawFunctor(wvInstance, &android::WebView::drawGL, + invScreenRect, scale, extras); + wvInstance->setFunctor((Functor*) functor); + } else { + functor->updateInvScreenRect(invScreenRect); + functor->updateScale(scale); + functor->updateExtras(extras); + } - WebCore::IntRect webViewRect = jrect_to_webrect(env, jviewrect); - functor->updateViewRect(webViewRect); + WebCore::IntRect rect = jrect_to_webrect(env, jscreenrect); + functor->updateScreenRect(rect); return (jint)functor; } @@ -835,20 +838,21 @@ static jint nativeGetDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView) { return (jint) wvInstance->getFunctor(); } -static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView, jobject jrect, - jobject jviewrect, jobject jvisiblerect, jfloat scale) { +static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView, + jobject jinvscreenrect, jobject jscreenrect, + jobject jvisiblecontentrect, jfloat scale) { WebView *wvInstance = (WebView*) nativeView; if (wvInstance) { GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor(); if (functor) { - WebCore::IntRect viewRect = jrect_to_webrect(env, jrect); - functor->updateRect(viewRect); + WebCore::IntRect invScreenRect = jrect_to_webrect(env, jinvscreenrect); + functor->updateInvScreenRect(invScreenRect); - SkRect visibleRect = jrectf_to_rect(env, jvisiblerect); - wvInstance->setVisibleRect(visibleRect); + SkRect visibleContentRect = jrectf_to_rect(env, jvisiblecontentrect); + wvInstance->setVisibleContentRect(visibleContentRect); - WebCore::IntRect webViewRect = jrect_to_webrect(env, jviewrect); - functor->updateViewRect(webViewRect); + WebCore::IntRect screenRect = jrect_to_webrect(env, jscreenrect); + functor->updateScreenRect(screenRect); functor->updateScale(scale); } @@ -882,12 +886,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); @@ -1094,7 +1092,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); @@ -1113,13 +1111,13 @@ static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl) #endif } -static int nativeScrollableLayer(JNIEnv* env, jobject jwebview, jint x, jint y, - jobject rect, jobject bounds) +static int nativeScrollableLayer(JNIEnv* env, jobject jwebview, jint nativeView, + jint x, jint y, jobject rect, jobject bounds) { - WebView* view = GET_NATIVE_VIEW(env, jwebview); - ALOG_ASSERT(view, "view not set in %s", __FUNCTION__); + WebView* webview = reinterpret_cast<WebView*>(nativeView); + ALOG_ASSERT(webview, "webview not set in %s", __FUNCTION__); SkIRect nativeRect, nativeBounds; - int id = view->scrollableLayer(x, y, &nativeRect, &nativeBounds); + int id = webview->scrollableLayer(x, y, &nativeRect, &nativeBounds); if (rect) GraphicsJNI::irect_to_jrect(nativeRect, env, rect); if (bounds) @@ -1127,15 +1125,15 @@ static int nativeScrollableLayer(JNIEnv* env, jobject jwebview, jint x, jint y, return id; } -static bool nativeScrollLayer(JNIEnv* env, jobject obj, jint layerId, jint x, - jint y) +static bool nativeScrollLayer(JNIEnv* env, jobject obj, + jint nativeView, jint layerId, jint x, jint y) { #if ENABLE(ANDROID_OVERFLOW_SCROLL) - WebView* view = GET_NATIVE_VIEW(env, obj); - view->scrollLayer(layerId, x, y); + WebView* webview = reinterpret_cast<WebView*>(nativeView); + webview->scrollLayer(layerId, x, y); //TODO: the below only needed for the SW rendering path - LayerAndroid* baseLayer = view->getBaseLayer(); + LayerAndroid* baseLayer = webview->getBaseLayer(); if (!baseLayer) return false; LayerAndroid* layer = baseLayer->findById(layerId); @@ -1233,7 +1231,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 }, @@ -1255,8 +1253,6 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeSetBaseLayer }, { "nativeGetBaseLayer", "()I", (void*) nativeGetBaseLayer }, - { "nativeReplaceBaseContent", "(I)V", - (void*) nativeReplaceBaseContent }, { "nativeCopyBaseContentToPicture", "(Landroid/graphics/Picture;)V", (void*) nativeCopyBaseContentToPicture }, { "nativeHasContent", "()Z", @@ -1279,9 +1275,9 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeTileProfilingGetFloat }, { "nativeStopGL", "()V", (void*) nativeStopGL }, - { "nativeScrollableLayer", "(IILandroid/graphics/Rect;Landroid/graphics/Rect;)I", + { "nativeScrollableLayer", "(IIILandroid/graphics/Rect;Landroid/graphics/Rect;)I", (void*) nativeScrollableLayer }, - { "nativeScrollLayer", "(III)Z", + { "nativeScrollLayer", "(IIII)Z", (void*) nativeScrollLayer }, { "nativeSetIsScrolling", "(Z)V", (void*) nativeSetIsScrolling }, |