summaryrefslogtreecommitdiffstats
path: root/gfx
diff options
context:
space:
mode:
authorben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-21 18:28:20 +0000
committerben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-21 18:28:20 +0000
commitf286f77eec2281993efe4dd408448903334d55eb (patch)
treef6d1a521ae0842a8313880bbb1436fef2c3ee497 /gfx
parent0940ddebe40365351c6fc53bfaf39bd7cd176249 (diff)
downloadchromium_src-f286f77eec2281993efe4dd408448903334d55eb.zip
chromium_src-f286f77eec2281993efe4dd408448903334d55eb.tar.gz
chromium_src-f286f77eec2281993efe4dd408448903334d55eb.tar.bz2
Implement initial ClipRect.
Move IntersectsClipRectInt and GetClipRect functions to CanvasSkia private, since they are only used internally. BUG=none TEST=see unittest. Review URL: http://codereview.chromium.org/2959014 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@53218 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gfx')
-rw-r--r--gfx/canvas.h7
-rw-r--r--gfx/canvas_direct2d.cc56
-rw-r--r--gfx/canvas_direct2d.h21
-rw-r--r--gfx/canvas_direct2d_unittest.cc27
-rw-r--r--gfx/canvas_skia.cc43
-rw-r--r--gfx/canvas_skia.h5
6 files changed, 106 insertions, 53 deletions
diff --git a/gfx/canvas.h b/gfx/canvas.h
index af1dd01..49c67f2 100644
--- a/gfx/canvas.h
+++ b/gfx/canvas.h
@@ -81,18 +81,11 @@ class Canvas {
// call Restore() more times than Save*().
virtual void Restore() = 0;
- // Retrieves the clip rectangle and sets it in the specified rectangle if any.
- // Returns true if the clip rect is non-empty.
- virtual bool GetClipRect(gfx::Rect* clip_rect) = 0;
-
// Wrapper function that takes integer arguments.
// Returns true if the clip is non-empty.
// See clipRect for specifics.
virtual bool ClipRectInt(int x, int y, int w, int h) = 0;
- // Test whether the provided rectangle intersects the current clip rect.
- virtual bool IntersectsClipRectInt(int x, int y, int w, int h) = 0;
-
// Wrapper function that takes integer arguments.
// See translate() for specifics.
virtual void TranslateInt(int x, int y) = 0;
diff --git a/gfx/canvas_direct2d.cc b/gfx/canvas_direct2d.cc
index 754882c..e69de1d 100644
--- a/gfx/canvas_direct2d.cc
+++ b/gfx/canvas_direct2d.cc
@@ -36,10 +36,17 @@ ID2D1Factory* CanvasDirect2D::d2d1_factory_ = NULL;
// CanvasDirect2D, public:
CanvasDirect2D::CanvasDirect2D(ID2D1RenderTarget* rt) : rt_(rt) {
+ // A RenderState entry is pushed onto the stack to track the clip count prior
+ // to any calls to Save*().
+ state_.push(RenderState());
rt_->BeginDraw();
}
CanvasDirect2D::~CanvasDirect2D() {
+ // Unwind any clips that were pushed outside of any Save*()/Restore() pairs.
+ int clip_count = state_.top().clip_count;
+ for (int i = 0; i < clip_count; ++i)
+ rt_->PopAxisAlignedClip();
rt_->EndDraw();
}
@@ -54,10 +61,7 @@ ID2D1Factory* CanvasDirect2D::GetD2D1Factory() {
// CanvasDirect2D, Canvas implementation:
void CanvasDirect2D::Save() {
- if (!drawing_state_block_)
- GetD2D1Factory()->CreateDrawingStateBlock(drawing_state_block_.Receive());
- rt_->SaveDrawingState(drawing_state_block_.get());
- layers_.push(NULL);
+ SaveInternal(NULL);
}
void CanvasDirect2D::SaveLayerAlpha(uint8 alpha) {
@@ -81,35 +85,45 @@ void CanvasDirect2D::SaveLayerAlpha(uint8 alpha,
D2D1_LAYER_OPTIONS_NONE),
layer);
}
- layers_.push(layer);
+ SaveInternal(layer);
}
void CanvasDirect2D::Restore() {
- ID2D1Layer* layer = layers_.top();
+ ID2D1Layer* layer = state_.top().layer;
if (layer) {
rt_->PopLayer();
layer->Release();
}
- layers_.pop();
- rt_->RestoreDrawingState(drawing_state_block_);
-}
-bool CanvasDirect2D::GetClipRect(gfx::Rect* clip_rect) {
- return false;
-}
+ int clip_count = state_.top().clip_count;
+ for (int i = 0; i < clip_count; ++i)
+ rt_->PopAxisAlignedClip();
-bool CanvasDirect2D::ClipRectInt(int x, int y, int w, int h) {
- return false;
+ state_.pop();
+ // The state_ stack should never be empty - we should always have at least one
+ // entry to hold a clip count when there is no active save/restore entry.
+ CHECK(!state_.empty()) << "Called Restore() once too often!";
+
+ rt_->RestoreDrawingState(drawing_state_block_);
}
-bool CanvasDirect2D::IntersectsClipRectInt(int x, int y, int w, int h) {
- return false;
+bool CanvasDirect2D::ClipRectInt(int x, int y, int w, int h) {
+ rt_->PushAxisAlignedClip(RectToRectF(x, y, w, h),
+ D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
+ // Increment the clip count so the call to PushAxisAlignedClip() can be
+ // balanced with a call to PopAxisAlignedClip in the next Restore().
+ ++state_.top().clip_count;
+ return w > 0 && h > 0;
}
void CanvasDirect2D::TranslateInt(int x, int y) {
+ rt_->SetTransform(D2D1::Matrix3x2F::Translation(static_cast<float>(x),
+ static_cast<float>(y)));
}
void CanvasDirect2D::ScaleInt(int x, int y) {
+ rt_->SetTransform(D2D1::Matrix3x2F::Scale(static_cast<float>(x),
+ static_cast<float>(y)));
}
void CanvasDirect2D::FillRectInt(int x, int y, int w, int h,
@@ -216,4 +230,14 @@ const CanvasSkia* CanvasDirect2D::AsCanvasSkia() const {
return NULL;
}
+////////////////////////////////////////////////////////////////////////////////
+// CanvasDirect2D, private:
+
+void CanvasDirect2D::SaveInternal(ID2D1Layer* layer) {
+ if (!drawing_state_block_)
+ GetD2D1Factory()->CreateDrawingStateBlock(drawing_state_block_.Receive());
+ rt_->SaveDrawingState(drawing_state_block_.get());
+ state_.push(RenderState(layer));
+}
+
} // namespace gfx
diff --git a/gfx/canvas_direct2d.h b/gfx/canvas_direct2d.h
index f4bc143..26c3f87 100644
--- a/gfx/canvas_direct2d.h
+++ b/gfx/canvas_direct2d.h
@@ -28,9 +28,7 @@ class CanvasDirect2D : public Canvas {
virtual void SaveLayerAlpha(uint8 alpha);
virtual void SaveLayerAlpha(uint8 alpha, const gfx::Rect& layer_bounds);
virtual void Restore();
- virtual bool GetClipRect(gfx::Rect* clip_rect);
virtual bool ClipRectInt(int x, int y, int w, int h);
- virtual bool IntersectsClipRectInt(int x, int y, int w, int h);
virtual void TranslateInt(int x, int y);
virtual void ScaleInt(int x, int y);
virtual void FillRectInt(int x, int y, int w, int h,
@@ -72,11 +70,28 @@ class CanvasDirect2D : public Canvas {
virtual const CanvasSkia* AsCanvasSkia() const;
private:
+ void SaveInternal(ID2D1Layer* layer);
+
ID2D1RenderTarget* rt_;
ScopedComPtr<ID2D1GdiInteropRenderTarget> interop_rt_;
ScopedComPtr<ID2D1DrawingStateBlock> drawing_state_block_;
static ID2D1Factory* d2d1_factory_;
- std::stack<ID2D1Layer*> layers_;
+
+ // Every time Save* is called, a RenderState object is pushed onto the
+ // RenderState stack.
+ struct RenderState {
+ explicit RenderState(ID2D1Layer* layer) : layer(layer), clip_count(0) {}
+ RenderState() : layer(NULL), clip_count(0) {}
+
+ // A D2D layer associated with this state, or NULL if there is no layer.
+ // The layer is created and owned by the Canvas.
+ ID2D1Layer* layer;
+ // The number of clip operations performed. This is used to balance calls to
+ // PushAxisAlignedClip with calls to PopAxisAlignedClip when Restore() is
+ // called.
+ int clip_count;
+ };
+ std::stack<RenderState> state_;
DISALLOW_COPY_AND_ASSIGN(CanvasDirect2D);
};
diff --git a/gfx/canvas_direct2d_unittest.cc b/gfx/canvas_direct2d_unittest.cc
index 0b5ce0f..7e2c734 100644
--- a/gfx/canvas_direct2d_unittest.cc
+++ b/gfx/canvas_direct2d_unittest.cc
@@ -154,3 +154,30 @@ TEST(CanvasDirect2D, PlatformPainting) {
canvas.EndPlatformPaint();
}
+TEST(CanvasDirect2D, ClipRect) {
+ TestWindow window;
+ gfx::CanvasDirect2D canvas(window.rt());
+
+ canvas.FillRectInt(SK_ColorGREEN, 0, 0, 500, 500);
+ canvas.ClipRectInt(20, 20, 120, 120);
+ canvas.FillRectInt(SK_ColorBLUE, 0, 0, 500, 500);
+}
+
+TEST(CanvasDirect2D, ClipRectWithTranslate) {
+ TestWindow window;
+ gfx::CanvasDirect2D canvas(window.rt());
+
+ // Repeat the same rendering as in ClipRect...
+ canvas.Save();
+ canvas.FillRectInt(SK_ColorGREEN, 0, 0, 500, 500);
+ canvas.ClipRectInt(20, 20, 120, 120);
+ canvas.FillRectInt(SK_ColorBLUE, 0, 0, 500, 500);
+ canvas.Restore();
+
+ // ... then translate, clip and fill again relative to the new origin.
+ canvas.Save();
+ canvas.TranslateInt(150, 150);
+ canvas.ClipRectInt(10, 10, 110, 110);
+ canvas.FillRectInt(SK_ColorRED, 0, 0, 500, 500);
+ canvas.Restore();
+}
diff --git a/gfx/canvas_skia.cc b/gfx/canvas_skia.cc
index d747f74..d5f2008 100644
--- a/gfx/canvas_skia.cc
+++ b/gfx/canvas_skia.cc
@@ -18,6 +18,16 @@
namespace gfx {
+////////////////////////////////////////////////////////////////////////////////
+// CanvasSkia, public:
+
+// static
+int CanvasSkia::DefaultCanvasTextAlignment() {
+ if (!base::i18n::IsRTL())
+ return gfx::Canvas::TEXT_ALIGN_LEFT;
+ return gfx::Canvas::TEXT_ALIGN_RIGHT;
+}
+
SkBitmap CanvasSkia::ExtractBitmap() const {
const SkBitmap& device_bitmap = getDevice()->accessBitmap(false);
@@ -54,19 +64,6 @@ void CanvasSkia::Restore() {
restore();
}
-bool CanvasSkia::GetClipRect(gfx::Rect* r) {
- SkRect clip;
- if (!getClipBounds(&clip)) {
- if (r)
- r->SetRect(0, 0, 0, 0);
- return false;
- }
- r->SetRect(SkScalarRound(clip.fLeft), SkScalarRound(clip.fTop),
- SkScalarRound(clip.fRight - clip.fLeft),
- SkScalarRound(clip.fBottom - clip.fTop));
- return true;
-}
-
bool CanvasSkia::ClipRectInt(int x, int y, int w, int h) {
SkRect new_clip;
new_clip.set(SkIntToScalar(x), SkIntToScalar(y),
@@ -74,13 +71,6 @@ bool CanvasSkia::ClipRectInt(int x, int y, int w, int h) {
return clipRect(new_clip);
}
-bool CanvasSkia::IntersectsClipRectInt(int x, int y, int w, int h) {
- SkRect clip;
- return getClipBounds(&clip) &&
- clip.intersect(SkIntToScalar(x), SkIntToScalar(y), SkIntToScalar(x + w),
- SkIntToScalar(y + h));
-}
-
void CanvasSkia::TranslateInt(int x, int y) {
translate(SkIntToScalar(x), SkIntToScalar(y));
}
@@ -314,11 +304,14 @@ const CanvasSkia* CanvasSkia::AsCanvasSkia() const {
return this;
}
-// static
-int CanvasSkia::DefaultCanvasTextAlignment() {
- if (!base::i18n::IsRTL())
- return gfx::Canvas::TEXT_ALIGN_LEFT;
- return gfx::Canvas::TEXT_ALIGN_RIGHT;
+////////////////////////////////////////////////////////////////////////////////
+// CanvasSkia, private:
+
+bool CanvasSkia::IntersectsClipRectInt(int x, int y, int w, int h) {
+ SkRect clip;
+ return getClipBounds(&clip) &&
+ clip.intersect(SkIntToScalar(x), SkIntToScalar(y), SkIntToScalar(x + w),
+ SkIntToScalar(y + h));
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/gfx/canvas_skia.h b/gfx/canvas_skia.h
index 115bd83..0e2f7e9 100644
--- a/gfx/canvas_skia.h
+++ b/gfx/canvas_skia.h
@@ -84,9 +84,7 @@ class CanvasSkia : public skia::PlatformCanvas,
virtual void SaveLayerAlpha(uint8 alpha);
virtual void SaveLayerAlpha(uint8 alpha, const gfx::Rect& layer_bounds);
virtual void Restore();
- virtual bool GetClipRect(gfx::Rect* clip_rect);
virtual bool ClipRectInt(int x, int y, int w, int h);
- virtual bool IntersectsClipRectInt(int x, int y, int w, int h);
virtual void TranslateInt(int x, int y);
virtual void ScaleInt(int x, int y);
virtual void FillRectInt(int x, int y, int w, int h,
@@ -128,6 +126,9 @@ class CanvasSkia : public skia::PlatformCanvas,
virtual const CanvasSkia* AsCanvasSkia() const;
private:
+ // Test whether the provided rectangle intersects the current clip rect.
+ bool IntersectsClipRectInt(int x, int y, int w, int h);
+
#if defined(OS_WIN)
// Draws text with the specified color, font and location. The text is
// aligned to the left, vertically centered, clipped to the region. If the