diff options
Diffstat (limited to 'Source/WebCore/platform')
4 files changed, 168 insertions, 11 deletions
diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp index 25441f4..7f4352b 100644 --- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp @@ -847,7 +847,7 @@ bool GraphicsLayerAndroid::paintContext(LayerAndroid* layer, // we can't do that because of transparency -- for now, we just create // a new picture every time. WebCore::PicturePile picture; - picture.setSize(IntSize(m_size.width(), m_size.height())); + picture.setSize(IntSize(rect.width(), rect.height())); // TODO: add content checks (text, opacity, etc.) picture.updatePicturesIfNeeded(this); diff --git a/Source/WebCore/platform/graphics/android/context/GraphicsOperation.h b/Source/WebCore/platform/graphics/android/context/GraphicsOperation.h index b1d91fb..c9c382a 100644 --- a/Source/WebCore/platform/graphics/android/context/GraphicsOperation.h +++ b/Source/WebCore/platform/graphics/android/context/GraphicsOperation.h @@ -84,6 +84,10 @@ public: virtual bool applyImpl(PlatformGraphicsContext* context) = 0; virtual ~Operation() {} + virtual const IntRect* opaqueRect() { return 0; } + virtual bool isOpaque() { return false; } + virtual void setOpaqueRect(const IntRect& bounds) {} + #if DEBUG_GRAPHICS_OPERATIONS typedef enum { UndefinedOperation // Matrix operations @@ -159,6 +163,15 @@ public: TYPE(UndefinedOperation) }; +class PossiblyOpaqueOperation : public Operation { +public: + virtual const IntRect* opaqueRect() { return &m_absoluteOpaqueRect; } + virtual void setOpaqueRect(const IntRect& bounds) { m_absoluteOpaqueRect = bounds; } + +private: + IntRect m_absoluteOpaqueRect; +}; + //************************************** // Matrix operations //************************************** @@ -290,7 +303,7 @@ private: // Drawing //************************************** -class DrawBitmapPattern : public Operation { +class DrawBitmapPattern : public PossiblyOpaqueOperation { public: DrawBitmapPattern(const SkBitmap& bitmap, const SkMatrix& matrix, CompositeOperator op, const FloatRect& destRect) @@ -299,7 +312,9 @@ public: context->drawBitmapPattern(m_bitmap, m_matrix, m_operator, m_destRect); return true; } + virtual bool isOpaque() { return m_bitmap.isOpaque(); } TYPE(DrawBitmapPatternOperation) + private: SkBitmap m_bitmap; SkMatrix m_matrix; @@ -307,7 +322,7 @@ private: FloatRect m_destRect; }; -class DrawBitmapRect : public Operation { +class DrawBitmapRect : public PossiblyOpaqueOperation { public: DrawBitmapRect(const SkBitmap& bitmap, const SkIRect& srcR, const SkRect& dstR, CompositeOperator op) @@ -316,6 +331,7 @@ public: context->drawBitmapRect(m_bitmap, &m_srcR, m_dstR, m_operator); return true; } + virtual bool isOpaque() { return m_bitmap.isOpaque(); } TYPE(DrawBitmapRectOperation) private: SkBitmap m_bitmap; @@ -443,7 +459,7 @@ private: WindRule m_fillRule; }; -class FillRect : public Operation { +class FillRect : public PossiblyOpaqueOperation { public: FillRect(const FloatRect& rect) : m_rect(rect), m_hasColor(false) {} void setColor(Color c) { m_color = c; m_hasColor = true; } @@ -454,6 +470,8 @@ public: context->fillRect(m_rect); return true; } + virtual bool isOpaque() { return (m_hasColor && !m_color.hasAlpha()) + || (!m_hasColor && SkColorGetA(m_state->fillColor) == 0xFF); } TYPE(FillRectOperation) private: FloatRect m_rect; diff --git a/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextRecording.cpp b/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextRecording.cpp index ec4c72a..355e52c 100644 --- a/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextRecording.cpp +++ b/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextRecording.cpp @@ -45,6 +45,8 @@ #define NEW_OP(X) new (operationHeap()) GraphicsOperation::X +#define USE_CLIPPING_PAINTER true + namespace WebCore { static FloatRect approximateTextBounds(size_t numGlyphs, @@ -288,6 +290,94 @@ static bool CompareRecordingDataOrder(const RecordingData* a, const RecordingDat return a->m_orderBy < b->m_orderBy; } +static IntRect enclosedIntRect(const FloatRect& rect) +{ + float left = ceilf(rect.x()); + float top = ceilf(rect.y()); + float width = floorf(rect.maxX()) - left; + float height = floorf(rect.maxY()) - top; + + return IntRect(clampToInteger(left), clampToInteger(top), + clampToInteger(width), clampToInteger(height)); +} + +#if USE_CLIPPING_PAINTER +class ClippingPainter { +public: + ClippingPainter(RecordingImpl* recording, + PlatformGraphicsContextSkia& context, + const SkMatrix& initialMatrix, + Vector<RecordingData*> &nodes) + : m_recording(recording) + , m_context(context) + , m_initialMatrix(initialMatrix) + , m_nodes(nodes) + , m_lastOperationId(0) + , m_currState(0) + {} + + void draw(const SkIRect& bounds) { + SkRegion coveredArea(bounds); + + drawWithClipRecursive(static_cast<int>(m_nodes.size()) - 1, coveredArea); + + while (m_currState) { + m_currState->exitState(&m_context); + m_currState = m_currState->parent(); + } + } + +private: + void drawOperation(RecordingData* node, const SkRegion& covered) + { + GraphicsOperation::Operation* op = node->m_operation; + m_recording->applyState(&m_context, m_currState, + m_lastOperationId, op->m_canvasState, node->m_orderBy); + m_currState = op->m_canvasState; + m_lastOperationId = node->m_orderBy; + + // if other opaque operations will cover the current one, clip that area out + // (and restore the clip immediately after drawing) + if (!covered.isEmpty()) { + m_context.save(); + m_context.canvas()->clipRegion(covered, SkRegion::kIntersect_Op); + } + op->apply(&(m_context)); + if (!covered.isEmpty()) + m_context.restore(); + } + + void drawWithClipRecursive(int index, const SkRegion& covered) + { + if (index < 0) + return; + RecordingData* recordingData = m_nodes[index]; + GraphicsOperation::Operation* op = recordingData->m_operation; + if (index != 0) { + const IntRect* opaqueRect = op->opaqueRect(); + if (!opaqueRect || opaqueRect->isEmpty()) { + drawWithClipRecursive(index - 1, covered); + } else { + SkRegion newCovered = covered; + SkRect mappedRect = *opaqueRect; + m_initialMatrix.mapRect(&mappedRect); + newCovered.op(enclosedIntRect(mappedRect), SkRegion::kDifference_Op); + if (!newCovered.isEmpty()) + drawWithClipRecursive(index - 1, newCovered); + } + } + drawOperation(recordingData, covered); + } + + RecordingImpl* m_recording; + PlatformGraphicsContextSkia& m_context; + const SkMatrix& m_initialMatrix; + const Vector<RecordingData*>& m_nodes; + size_t m_lastOperationId; + CanvasState* m_currState; +}; +#endif // USE_CLIPPING_PAINTER + void Recording::draw(SkCanvas* canvas) { if (!m_recording) { @@ -310,6 +400,10 @@ void Recording::draw(SkCanvas* canvas) int saveCount = canvas->getSaveCount(); nonCopyingSort(nodes.begin(), nodes.end(), CompareRecordingDataOrder); PlatformGraphicsContextSkia context(canvas); +#if USE_CLIPPING_PAINTER + ClippingPainter painter(recording(), context, canvas->getTotalMatrix(), nodes); + painter.draw(canvas->getTotalClip().getBounds()); +#else CanvasState* currState = 0; size_t lastOperationId = 0; for (size_t i = 0; i < count; i++) { @@ -325,6 +419,7 @@ void Recording::draw(SkCanvas* canvas) currState->exitState(&context); currState = currState->parent(); } +#endif if (saveCount != canvas->getSaveCount()) { ALOGW("Save/restore mismatch! %d vs. %d", saveCount, canvas->getSaveCount()); } @@ -353,6 +448,7 @@ PlatformGraphicsContextRecording::PlatformGraphicsContextRecording(Recording* re , m_isEmpty(true) , m_canvasProxy(this) { + ALOGV("RECORDING: begin"); if (mRecording) mRecording->setRecording(new RecordingImpl()); mMatrixStack.append(SkMatrix::I()); @@ -360,6 +456,11 @@ PlatformGraphicsContextRecording::PlatformGraphicsContextRecording(Recording* re pushStateOperation(new (canvasStateHeap()) CanvasState(0)); } +PlatformGraphicsContextRecording::~PlatformGraphicsContextRecording() +{ + ALOGV("RECORDING: end"); +} + bool PlatformGraphicsContextRecording::isPaintingDisabled() { return !mRecording; @@ -543,11 +644,13 @@ const SkMatrix& PlatformGraphicsContextRecording::getTotalMatrix() void PlatformGraphicsContextRecording::addInnerRoundedRectClip(const IntRect& rect, int thickness) { + mRecordingStateStack.last().setHasComplexClip(); appendStateOperation(NEW_OP(InnerRoundedRectClip)(rect, thickness)); } void PlatformGraphicsContextRecording::canvasClip(const Path& path) { + mRecordingStateStack.last().setHasComplexClip(); clip(path); } @@ -560,6 +663,7 @@ bool PlatformGraphicsContextRecording::clip(const FloatRect& rect) bool PlatformGraphicsContextRecording::clip(const Path& path) { + mRecordingStateStack.last().setHasComplexClip(); clipState(path.boundingRect()); appendStateOperation(NEW_OP(ClipPath)(path)); return true; @@ -574,18 +678,21 @@ bool PlatformGraphicsContextRecording::clipConvexPolygon(size_t numPoints, bool PlatformGraphicsContextRecording::clipOut(const IntRect& r) { + mRecordingStateStack.last().setHasComplexClip(); appendStateOperation(NEW_OP(ClipOut)(r)); return true; } bool PlatformGraphicsContextRecording::clipOut(const Path& path) { + mRecordingStateStack.last().setHasComplexClip(); appendStateOperation(NEW_OP(ClipPath)(path, true)); return true; } bool PlatformGraphicsContextRecording::clipPath(const Path& pathToClip, WindRule clipRule) { + mRecordingStateStack.last().setHasComplexClip(); clipState(pathToClip.boundingRect()); GraphicsOperation::ClipPath* operation = NEW_OP(ClipPath)(pathToClip); operation->setWindRule(clipRule); @@ -771,7 +878,7 @@ void PlatformGraphicsContextRecording::clipState(const FloatRect& clip) void PlatformGraphicsContextRecording::pushStateOperation(CanvasState* canvasState) { - ALOGV("pushStateOperation: %p(isLayer=%d)", canvasState, canvasState->isTransparencyLayer()); + ALOGV("RECORDING: pushStateOperation: %p(isLayer=%d)", canvasState, canvasState->isTransparencyLayer()); mRecordingStateStack.append(canvasState); mRecording->recording()->addCanvasState(canvasState); } @@ -780,14 +887,15 @@ void PlatformGraphicsContextRecording::popStateOperation() { RecordingState state = mRecordingStateStack.last(); mRecordingStateStack.removeLast(); + mOperationState = 0; if (!state.mHasDrawing) { - ALOGV("popStateOperation is deleting %p(isLayer=%d)", + ALOGV("RECORDING: popStateOperation is deleting %p(isLayer=%d)", state.mCanvasState, state.mCanvasState->isTransparencyLayer()); mRecording->recording()->removeCanvasState(state.mCanvasState); state.mCanvasState->~CanvasState(); canvasStateHeap()->rewindTo(state.mCanvasState); } else { - ALOGV("popStateOperation: %p(isLayer=%d)", + ALOGV("RECORDING: popStateOperation: %p(isLayer=%d)", state.mCanvasState, state.mCanvasState->isTransparencyLayer()); // Make sure we propagate drawing upwards so we don't delete our parent mRecordingStateStack.last().mHasDrawing = true; @@ -839,6 +947,20 @@ IntRect PlatformGraphicsContextRecording::calculateFinalBounds(FloatRect bounds) return enclosingIntRect(translated); } +IntRect PlatformGraphicsContextRecording::calculateCoveredBounds(FloatRect bounds) +{ + SkRect translated; + mCurrentMatrix->mapRect(&translated, bounds); + FloatRect ftrect = translated; + if (mRecordingStateStack.last().mHasClip + && !translated.intersect(mRecordingStateStack.last().mBounds)) { + ALOGV("Operation opaque area=" FLOAT_RECT_FORMAT " clipped out by clip=" FLOAT_RECT_FORMAT, + FLOAT_RECT_ARGS(ftrect), FLOAT_RECT_ARGS(mRecordingStateStack.last().mBounds)); + return IntRect(); + } + return enclosedIntRect(translated); +} + void PlatformGraphicsContextRecording::appendDrawingOperation( GraphicsOperation::Operation* operation, const FloatRect& untranslatedBounds) { @@ -852,19 +974,28 @@ void PlatformGraphicsContextRecording::appendDrawingOperation( WebCore::IntRect ibounds = calculateFinalBounds(untranslatedBounds); if (ibounds.isEmpty()) { - ALOGV("Operation %s() was clipped out", operation->name()); + ALOGV("RECORDING: Operation %s() was clipped out", operation->name()); operation->~Operation(); operationHeap()->rewindTo(operation); return; } - ALOGV("appendOperation %p->%s()", operation, operation->name()); + if (operation->isOpaque() + && !untranslatedBounds.isEmpty() + && operation->m_state->alpha == 1.0f + && mCurrentMatrix->rectStaysRect() + && !state.mHasComplexClip) { + // if the operation maps to an opaque rect, record the area it will cover + operation->setOpaqueRect(calculateCoveredBounds(untranslatedBounds)); + } + ALOGV("RECORDING: appendOperation %p->%s() bounds " INT_RECT_FORMAT, operation, operation->name(), + INT_RECT_ARGS(ibounds)); RecordingData* data = new RecordingData(operation, mRecording->recording()->m_nodeCount++); mRecording->recording()->m_tree.insert(ibounds, data); } void PlatformGraphicsContextRecording::appendStateOperation(GraphicsOperation::Operation* operation) { - ALOGV("appendOperation %p->%s()", operation, operation->name()); + ALOGV("RECORDING: appendOperation %p->%s()", operation, operation->name()); RecordingData* data = new RecordingData(operation, mRecording->recording()->m_nodeCount++); mRecordingStateStack.last().mCanvasState->adoptAndAppend(data); } diff --git a/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextRecording.h b/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextRecording.h index 17906d8..d62eb8a 100644 --- a/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextRecording.h +++ b/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextRecording.h @@ -39,6 +39,8 @@ class Operation; class CanvasState; class LinearAllocator; class RecordingImpl; +class PlatformGraphicsContextSkia; +class RecordingData; class Recording : public SkRefCnt { public: @@ -58,7 +60,7 @@ private: class PlatformGraphicsContextRecording : public PlatformGraphicsContext { public: PlatformGraphicsContextRecording(Recording* picture); - virtual ~PlatformGraphicsContextRecording() {} + virtual ~PlatformGraphicsContextRecording(); virtual bool isPaintingDisabled(); virtual SkCanvas* recordingCanvas(); @@ -157,6 +159,7 @@ private: void pushMatrix(); void popMatrix(); IntRect calculateFinalBounds(FloatRect bounds); + IntRect calculateCoveredBounds(FloatRect bounds); LinearAllocator* operationHeap(); LinearAllocator* canvasStateHeap(); @@ -170,15 +173,19 @@ private: : mCanvasState(state) , mHasDrawing(false) , mHasClip(false) + , mHasComplexClip(false) {} RecordingState(const RecordingState& other) : mCanvasState(other.mCanvasState) , mHasDrawing(other.mHasDrawing) , mHasClip(other.mHasClip) + , mHasComplexClip(false) , mBounds(other.mBounds) {} + void setHasComplexClip() { mHasComplexClip = true; } + void clip(const FloatRect& rect) { if (mHasClip) @@ -192,6 +199,7 @@ private: CanvasState* mCanvasState; bool mHasDrawing; bool mHasClip; + bool mHasComplexClip; FloatRect mBounds; }; Vector<RecordingState> mRecordingStateStack; |