summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp2
-rw-r--r--Source/WebCore/platform/graphics/android/context/GraphicsOperation.h24
-rw-r--r--Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextRecording.cpp143
-rw-r--r--Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextRecording.h10
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;