diff options
author | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-21 18:28:20 +0000 |
---|---|---|
committer | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-21 18:28:20 +0000 |
commit | f286f77eec2281993efe4dd408448903334d55eb (patch) | |
tree | f6d1a521ae0842a8313880bbb1436fef2c3ee497 /gfx | |
parent | 0940ddebe40365351c6fc53bfaf39bd7cd176249 (diff) | |
download | chromium_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.h | 7 | ||||
-rw-r--r-- | gfx/canvas_direct2d.cc | 56 | ||||
-rw-r--r-- | gfx/canvas_direct2d.h | 21 | ||||
-rw-r--r-- | gfx/canvas_direct2d_unittest.cc | 27 | ||||
-rw-r--r-- | gfx/canvas_skia.cc | 43 | ||||
-rw-r--r-- | gfx/canvas_skia.h | 5 |
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 |