diff options
-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 | ||||
-rw-r--r-- | views/border.cc | 26 |
7 files changed, 112 insertions, 73 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 diff --git a/views/border.cc b/views/border.cc index 1259808..1dce649 100644 --- a/views/border.cc +++ b/views/border.cc @@ -34,30 +34,16 @@ SolidBorder::SolidBorder(int thickness, SkColor color) } void SolidBorder::Paint(const View& view, gfx::Canvas* canvas) const { - gfx::Rect clip_rect; - if (!canvas->GetClipRect(&clip_rect)) - return; // Empty clip rectangle, nothing to paint. - // Top border. - gfx::Rect border_bounds(0, 0, view.width(), insets_.top()); - if (clip_rect.Intersects(border_bounds)) - canvas->FillRectInt(color_, 0, 0, view.width(), insets_.top()); + canvas->FillRectInt(color_, 0, 0, view.width(), insets_.top()); // Left border. - border_bounds.SetRect(0, 0, insets_.left(), view.height()); - if (clip_rect.Intersects(border_bounds)) - canvas->FillRectInt(color_, 0, 0, insets_.left(), view.height()); + canvas->FillRectInt(color_, 0, 0, insets_.left(), view.height()); // Bottom border. - border_bounds.SetRect(0, view.height() - insets_.bottom(), - view.width(), insets_.bottom()); - if (clip_rect.Intersects(border_bounds)) - canvas->FillRectInt(color_, 0, view.height() - insets_.bottom(), - view.width(), insets_.bottom()); + canvas->FillRectInt(color_, 0, view.height() - insets_.bottom(), + view.width(), insets_.bottom()); // Right border. - border_bounds.SetRect(view.width() - insets_.right(), 0, - insets_.right(), view.height()); - if (clip_rect.Intersects(border_bounds)) - canvas->FillRectInt(color_, view.width() - insets_.right(), 0, - insets_.right(), view.height()); + canvas->FillRectInt(color_, view.width() - insets_.right(), 0, + insets_.right(), view.height()); } void SolidBorder::GetInsets(gfx::Insets* insets) const { |