OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "gfx/canvas_direct2d.h" | |
6 | |
7 #include "base/scoped_ptr.h" | |
8 #include "gfx/brush.h" | |
9 #include "gfx/rect.h" | |
10 | |
11 namespace { | |
12 | |
13 // Converts a SkColor to a ColorF. | |
14 D2D1_COLOR_F SkColorToColorF(SkColor color) { | |
15 return D2D1::ColorF(static_cast<float>(SkColorGetR(color)) / 0xFF, | |
16 static_cast<float>(SkColorGetG(color)) / 0xFF, | |
17 static_cast<float>(SkColorGetB(color)) / 0xFF, | |
18 static_cast<float>(SkColorGetA(color)) / 0xFF); | |
19 } | |
20 | |
21 D2D1_RECT_F RectToRectF(int x, int y, int w, int h) { | |
22 return D2D1::RectF(static_cast<float>(x), static_cast<float>(y), | |
23 static_cast<float>(x + w), static_cast<float>(y + h)); | |
24 } | |
25 | |
26 D2D1_RECT_F RectToRectF(const gfx::Rect& rect) { | |
27 return RectToRectF(rect.x(), rect.y(), rect.width(), rect.height()); | |
28 } | |
29 | |
30 D2D1_POINT_2F PointToPoint2F(int x, int y) { | |
31 return D2D1::Point2F(static_cast<float>(x), static_cast<float>(y)); | |
32 } | |
33 | |
34 D2D1_BITMAP_INTERPOLATION_MODE FilterToInterpolationMode(bool filter) { | |
35 return filter ? D2D1_BITMAP_INTERPOLATION_MODE_LINEAR | |
36 : D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR; | |
37 } | |
38 | |
39 // Creates a Direct2D bitmap object from the contents of a SkBitmap. The caller | |
40 // is responsible for releasing this object. | |
41 ID2D1Bitmap* CreateD2D1BitmapFromSkBitmap(ID2D1RenderTarget* render_target, | |
42 const SkBitmap& bitmap) { | |
43 ID2D1Bitmap* d2d1_bitmap = NULL; | |
44 HRESULT hr = render_target->CreateBitmap( | |
45 D2D1::SizeU(bitmap.width(), bitmap.height()), | |
46 NULL, | |
47 NULL, | |
48 D2D1::BitmapProperties( | |
49 D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, | |
50 D2D1_ALPHA_MODE_IGNORE)), | |
51 &d2d1_bitmap); | |
52 if (FAILED(hr)) | |
53 return NULL; | |
54 bitmap.lockPixels(); | |
55 d2d1_bitmap->CopyFromMemory(NULL, bitmap.getPixels(), bitmap.rowBytes()); | |
56 bitmap.unlockPixels(); | |
57 return d2d1_bitmap; | |
58 } | |
59 | |
60 // Creates a Direct2D bitmap brush from the contents of a SkBitmap. The caller | |
61 // is responsible for releasing this object. | |
62 ID2D1Brush* CreateD2D1BrushFromSkBitmap(ID2D1RenderTarget* render_target, | |
63 const SkBitmap& bitmap, | |
64 D2D1_EXTEND_MODE extend_mode_x, | |
65 D2D1_EXTEND_MODE extend_mode_y) { | |
66 ScopedComPtr<ID2D1Bitmap> d2d1_bitmap( | |
67 CreateD2D1BitmapFromSkBitmap(render_target, bitmap)); | |
68 | |
69 ID2D1BitmapBrush* brush = NULL; | |
70 render_target->CreateBitmapBrush( | |
71 d2d1_bitmap, | |
72 D2D1::BitmapBrushProperties(extend_mode_x, extend_mode_y), | |
73 D2D1::BrushProperties(), | |
74 &brush); | |
75 return brush; | |
76 } | |
77 | |
78 // A platform wrapper for a Direct2D brush that makes sure the underlying | |
79 // ID2D1Brush COM object is released when this object is destroyed. | |
80 class Direct2DBrush : public gfx::Brush { | |
81 public: | |
82 explicit Direct2DBrush(ID2D1Brush* brush) : brush_(brush) { | |
83 } | |
84 | |
85 ID2D1Brush* brush() const { return brush_.get(); } | |
86 | |
87 private: | |
88 ScopedComPtr<ID2D1Brush> brush_; | |
89 | |
90 DISALLOW_COPY_AND_ASSIGN(Direct2DBrush); | |
91 }; | |
92 | |
93 | |
94 } // namespace | |
95 | |
96 namespace gfx { | |
97 | |
98 // static | |
99 ID2D1Factory* CanvasDirect2D::d2d1_factory_ = NULL; | |
100 | |
101 //////////////////////////////////////////////////////////////////////////////// | |
102 // CanvasDirect2D, public: | |
103 | |
104 CanvasDirect2D::CanvasDirect2D(ID2D1RenderTarget* rt) : rt_(rt) { | |
105 // A RenderState entry is pushed onto the stack to track the clip count prior | |
106 // to any calls to Save*(). | |
107 state_.push(RenderState()); | |
108 rt_->BeginDraw(); | |
109 } | |
110 | |
111 CanvasDirect2D::~CanvasDirect2D() { | |
112 // Unwind any clips that were pushed outside of any Save*()/Restore() pairs. | |
113 int clip_count = state_.top().clip_count; | |
114 for (int i = 0; i < clip_count; ++i) | |
115 rt_->PopAxisAlignedClip(); | |
116 rt_->EndDraw(); | |
117 } | |
118 | |
119 // static | |
120 ID2D1Factory* CanvasDirect2D::GetD2D1Factory() { | |
121 if (!d2d1_factory_) | |
122 D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &d2d1_factory_); | |
123 return d2d1_factory_; | |
124 } | |
125 | |
126 //////////////////////////////////////////////////////////////////////////////// | |
127 // CanvasDirect2D, Canvas implementation: | |
128 | |
129 void CanvasDirect2D::Save() { | |
130 SaveInternal(NULL); | |
131 } | |
132 | |
133 void CanvasDirect2D::SaveLayerAlpha(uint8 alpha) { | |
134 SaveLayerAlpha(alpha, gfx::Rect()); | |
135 } | |
136 | |
137 void CanvasDirect2D::SaveLayerAlpha(uint8 alpha, | |
138 const gfx::Rect& layer_bounds) { | |
139 D2D1_RECT_F bounds = D2D1::InfiniteRect(); | |
140 if (!layer_bounds.IsEmpty()) | |
141 bounds = RectToRectF(layer_bounds); | |
142 ID2D1Layer* layer = NULL; | |
143 HRESULT hr = rt_->CreateLayer(NULL, &layer); | |
144 if (SUCCEEDED(hr)) { | |
145 rt_->PushLayer(D2D1::LayerParameters(bounds, | |
146 NULL, | |
147 D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, | |
148 D2D1::IdentityMatrix(), | |
149 static_cast<float>(alpha) / 0xFF, | |
150 NULL, | |
151 D2D1_LAYER_OPTIONS_NONE), | |
152 layer); | |
153 } | |
154 SaveInternal(layer); | |
155 } | |
156 | |
157 void CanvasDirect2D::Restore() { | |
158 ID2D1Layer* layer = state_.top().layer; | |
159 if (layer) { | |
160 rt_->PopLayer(); | |
161 layer->Release(); | |
162 } | |
163 | |
164 int clip_count = state_.top().clip_count; | |
165 for (int i = 0; i < clip_count; ++i) | |
166 rt_->PopAxisAlignedClip(); | |
167 | |
168 state_.pop(); | |
169 // The state_ stack should never be empty - we should always have at least one | |
170 // entry to hold a clip count when there is no active save/restore entry. | |
171 CHECK(!state_.empty()) << "Called Restore() once too often!"; | |
172 | |
173 rt_->RestoreDrawingState(drawing_state_block_); | |
174 } | |
175 | |
176 bool CanvasDirect2D::ClipRectInt(int x, int y, int w, int h) { | |
177 rt_->PushAxisAlignedClip(RectToRectF(x, y, w, h), | |
178 D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); | |
179 // Increment the clip count so the call to PushAxisAlignedClip() can be | |
180 // balanced with a call to PopAxisAlignedClip in the next Restore(). | |
181 ++state_.top().clip_count; | |
182 return w > 0 && h > 0; | |
183 } | |
184 | |
185 void CanvasDirect2D::TranslateInt(int x, int y) { | |
186 D2D1_MATRIX_3X2_F raw; | |
187 rt_->GetTransform(&raw); | |
188 D2D1::Matrix3x2F transform(raw._11, raw._12, raw._21, raw._22, raw._31, | |
189 raw._32); | |
190 transform = D2D1::Matrix3x2F::Translation(static_cast<float>(x), | |
191 static_cast<float>(y)) * transform; | |
192 rt_->SetTransform(transform); | |
193 } | |
194 | |
195 void CanvasDirect2D::ScaleInt(int x, int y) { | |
196 D2D1_MATRIX_3X2_F raw; | |
197 rt_->GetTransform(&raw); | |
198 D2D1::Matrix3x2F transform(raw._11, raw._12, raw._21, raw._22, raw._31, | |
199 raw._32); | |
200 transform = D2D1::Matrix3x2F::Scale(static_cast<float>(x), | |
201 static_cast<float>(y)) * transform; | |
202 rt_->SetTransform(transform); | |
203 } | |
204 | |
205 void CanvasDirect2D::FillRectInt(const SkColor& color, | |
206 int x, int y, int w, int h) { | |
207 ScopedComPtr<ID2D1SolidColorBrush> solid_brush; | |
208 rt_->CreateSolidColorBrush(SkColorToColorF(color), solid_brush.Receive()); | |
209 rt_->FillRectangle(RectToRectF(x, y, w, h), solid_brush); | |
210 } | |
211 | |
212 void CanvasDirect2D::FillRectInt(const SkColor& color, | |
213 int x, int y, int w, int h, | |
214 SkXfermode::Mode mode) { | |
215 NOTIMPLEMENTED(); | |
216 } | |
217 | |
218 void CanvasDirect2D::FillRectInt(const gfx::Brush* brush, | |
219 int x, int y, int w, int h) { | |
220 const Direct2DBrush* d2d_brush = static_cast<const Direct2DBrush*>(brush); | |
221 rt_->FillRectangle(RectToRectF(x, y, w, h), d2d_brush->brush()); | |
222 } | |
223 | |
224 void CanvasDirect2D::DrawRectInt(const SkColor& color, | |
225 int x, int y, int w, int h) { | |
226 ScopedComPtr<ID2D1SolidColorBrush> solid_brush; | |
227 rt_->CreateSolidColorBrush(SkColorToColorF(color), solid_brush.Receive()); | |
228 rt_->DrawRectangle(RectToRectF(x, y, w, h), solid_brush); | |
229 } | |
230 | |
231 void CanvasDirect2D::DrawRectInt(const SkColor& color, | |
232 int x, int y, int w, int h, | |
233 SkXfermode::Mode mode) { | |
234 NOTIMPLEMENTED(); | |
235 } | |
236 | |
237 void CanvasDirect2D::DrawRectInt(int x, int y, int w, int h, | |
238 const SkPaint& paint) { | |
239 NOTIMPLEMENTED(); | |
240 } | |
241 | |
242 void CanvasDirect2D::DrawLineInt(const SkColor& color, | |
243 int x1, int y1, | |
244 int x2, int y2) { | |
245 ScopedComPtr<ID2D1SolidColorBrush> solid_brush; | |
246 rt_->CreateSolidColorBrush(SkColorToColorF(color), solid_brush.Receive()); | |
247 rt_->DrawLine(PointToPoint2F(x1, y1), PointToPoint2F(x2, y2), solid_brush); | |
248 } | |
249 | |
250 void CanvasDirect2D::DrawBitmapInt(const SkBitmap& bitmap, int x, int y) { | |
251 ScopedComPtr<ID2D1Bitmap> d2d1_bitmap( | |
252 CreateD2D1BitmapFromSkBitmap(rt_, bitmap)); | |
253 rt_->DrawBitmap(d2d1_bitmap, | |
254 RectToRectF(x, y, bitmap.width(), bitmap.height()), | |
255 1.0f, | |
256 D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR, | |
257 RectToRectF(0, 0, bitmap.width(), bitmap.height())); | |
258 } | |
259 | |
260 void CanvasDirect2D::DrawBitmapInt(const SkBitmap& bitmap, | |
261 int x, int y, | |
262 const SkPaint& paint) { | |
263 NOTIMPLEMENTED(); | |
264 } | |
265 | |
266 void CanvasDirect2D::DrawBitmapInt(const SkBitmap& bitmap, | |
267 int src_x, int src_y, int src_w, int src_h, | |
268 int dest_x, int dest_y, | |
269 int dest_w, int dest_h, | |
270 bool filter) { | |
271 ScopedComPtr<ID2D1Bitmap> d2d1_bitmap( | |
272 CreateD2D1BitmapFromSkBitmap(rt_, bitmap)); | |
273 rt_->DrawBitmap(d2d1_bitmap, | |
274 RectToRectF(dest_x, dest_y, dest_w, dest_h), | |
275 1.0f, | |
276 FilterToInterpolationMode(filter), | |
277 RectToRectF(src_x, src_y, src_w, src_h)); | |
278 } | |
279 | |
280 void CanvasDirect2D::DrawBitmapInt(const SkBitmap& bitmap, | |
281 int src_x, int src_y, int src_w, int src_h, | |
282 int dest_x, int dest_y, | |
283 int dest_w, int dest_h, | |
284 bool filter, | |
285 const SkPaint& paint) { | |
286 NOTIMPLEMENTED(); | |
287 } | |
288 | |
289 void CanvasDirect2D::DrawStringInt(const string16& text, | |
290 const gfx::Font& font, | |
291 const SkColor& color, | |
292 int x, int y, int w, int h) { | |
293 NOTIMPLEMENTED(); | |
294 } | |
295 | |
296 void CanvasDirect2D::DrawStringInt(const string16& text, | |
297 const gfx::Font& font, | |
298 const SkColor& color, | |
299 const gfx::Rect& display_rect) { | |
300 NOTIMPLEMENTED(); | |
301 } | |
302 | |
303 void CanvasDirect2D::DrawStringInt(const string16& text, | |
304 const gfx::Font& font, | |
305 const SkColor& color, | |
306 int x, int y, int w, int h, | |
307 int flags) { | |
308 NOTIMPLEMENTED(); | |
309 } | |
310 | |
311 void CanvasDirect2D::DrawFocusRect(int x, int y, int width, int height) { | |
312 NOTIMPLEMENTED(); | |
313 } | |
314 | |
315 void CanvasDirect2D::TileImageInt(const SkBitmap& bitmap, | |
316 int x, int y, int w, int h) { | |
317 ScopedComPtr<ID2D1Brush> brush( | |
318 CreateD2D1BrushFromSkBitmap(rt_, bitmap, D2D1_EXTEND_MODE_WRAP, | |
319 D2D1_EXTEND_MODE_WRAP)); | |
320 rt_->FillRectangle(RectToRectF(x, y, w, h), brush); | |
321 } | |
322 | |
323 void CanvasDirect2D::TileImageInt(const SkBitmap& bitmap, | |
324 int src_x, int src_y, | |
325 int dest_x, int dest_y, int w, int h) { | |
326 NOTIMPLEMENTED(); | |
327 } | |
328 | |
329 gfx::NativeDrawingContext CanvasDirect2D::BeginPlatformPaint() { | |
330 DCHECK(!interop_rt_.get()); | |
331 interop_rt_.QueryFrom(rt_); | |
332 HDC dc = NULL; | |
333 if (interop_rt_.get()) | |
334 interop_rt_->GetDC(D2D1_DC_INITIALIZE_MODE_COPY, &dc); | |
335 return dc; | |
336 } | |
337 | |
338 void CanvasDirect2D::EndPlatformPaint() { | |
339 DCHECK(interop_rt_.get()); | |
340 interop_rt_->ReleaseDC(NULL); | |
341 interop_rt_.release(); | |
342 } | |
343 | |
344 CanvasSkia* CanvasDirect2D::AsCanvasSkia() { | |
345 return NULL; | |
346 } | |
347 | |
348 const CanvasSkia* CanvasDirect2D::AsCanvasSkia() const { | |
349 return NULL; | |
350 } | |
351 | |
352 //////////////////////////////////////////////////////////////////////////////// | |
353 // CanvasDirect2D, private: | |
354 | |
355 void CanvasDirect2D::SaveInternal(ID2D1Layer* layer) { | |
356 if (!drawing_state_block_) | |
357 GetD2D1Factory()->CreateDrawingStateBlock(drawing_state_block_.Receive()); | |
358 rt_->SaveDrawingState(drawing_state_block_.get()); | |
359 state_.push(RenderState(layer)); | |
360 } | |
361 | |
362 } // namespace gfx | |
OLD | NEW |