OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "skia/ext/bitmap_platform_device_win.h" | 5 #include "skia/ext/bitmap_platform_device_win.h" |
6 | 6 |
7 #include "base/gfx/gdi_util.h" | |
8 #include "base/logging.h" | |
9 #include "SkMatrix.h" | 7 #include "SkMatrix.h" |
| 8 #include "SkRefCnt.h" |
10 #include "SkRegion.h" | 9 #include "SkRegion.h" |
11 #include "SkUtils.h" | 10 #include "SkUtils.h" |
12 | 11 |
13 namespace skia { | 12 namespace skia { |
14 | 13 |
15 // When Windows draws text, is sets the fourth byte (which Skia uses for alpha) | 14 // When Windows draws text, is sets the fourth byte (which Skia uses for alpha) |
16 // to zero. This means that if we try compositing with text that Windows has | 15 // to zero. This means that if we try compositing with text that Windows has |
17 // drawn, we get invalid color values (if the alpha is 0, the other channels | 16 // drawn, we get invalid color values (if the alpha is 0, the other channels |
18 // should be 0 since Skia uses premultiplied colors) and strange results. | 17 // should be 0 since Skia uses premultiplied colors) and strange results. |
19 // | 18 // |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
93 // See the declaration of kMagicTransparencyColor at the top of the file. | 92 // See the declaration of kMagicTransparencyColor at the top of the file. |
94 void FixupAlphaBeforeCompositing(uint32_t* pixel) { | 93 void FixupAlphaBeforeCompositing(uint32_t* pixel) { |
95 if (*pixel == kMagicTransparencyColor) | 94 if (*pixel == kMagicTransparencyColor) |
96 *pixel = 0; | 95 *pixel = 0; |
97 else | 96 else |
98 *pixel |= 0xFF000000; | 97 *pixel |= 0xFF000000; |
99 } | 98 } |
100 | 99 |
101 } // namespace | 100 } // namespace |
102 | 101 |
103 class BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData | 102 class BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData : public SkRefCnt { |
104 : public base::RefCounted<BitmapPlatformDeviceWinData> { | |
105 public: | 103 public: |
106 explicit BitmapPlatformDeviceWinData(HBITMAP hbitmap); | 104 explicit BitmapPlatformDeviceWinData(HBITMAP hbitmap); |
107 | 105 |
108 // Create/destroy hdc_, which is the memory DC for our bitmap data. | 106 // Create/destroy hdc_, which is the memory DC for our bitmap data. |
109 HDC GetBitmapDC(); | 107 HDC GetBitmapDC(); |
110 void ReleaseBitmapDC(); | 108 void ReleaseBitmapDC(); |
111 bool IsBitmapDCCreated() const; | 109 bool IsBitmapDCCreated() const; |
112 | 110 |
113 // Sets the transform and clip operations. This will not update the DC, | 111 // Sets the transform and clip operations. This will not update the DC, |
114 // but will mark the config as dirty. The next call of LoadConfig will | 112 // but will mark the config as dirty. The next call of LoadConfig will |
(...skipping 22 matching lines...) Expand all Loading... |
137 bool config_dirty_; | 135 bool config_dirty_; |
138 | 136 |
139 // Translation assigned to the DC: we need to keep track of this separately | 137 // Translation assigned to the DC: we need to keep track of this separately |
140 // so it can be updated even if the DC isn't created yet. | 138 // so it can be updated even if the DC isn't created yet. |
141 SkMatrix transform_; | 139 SkMatrix transform_; |
142 | 140 |
143 // The current clipping | 141 // The current clipping |
144 SkRegion clip_region_; | 142 SkRegion clip_region_; |
145 | 143 |
146 private: | 144 private: |
147 friend class base::RefCounted<BitmapPlatformDeviceWinData>; | 145 virtual ~BitmapPlatformDeviceWinData(); |
148 ~BitmapPlatformDeviceWinData(); | |
149 | 146 |
150 DISALLOW_EVIL_CONSTRUCTORS(BitmapPlatformDeviceWinData); | 147 // Copy & assign are not supported. |
| 148 BitmapPlatformDeviceWinData(const BitmapPlatformDeviceWinData&); |
| 149 BitmapPlatformDeviceWinData& operator=(const BitmapPlatformDeviceWinData&); |
151 }; | 150 }; |
152 | 151 |
153 BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::BitmapPlatformDeviceWinDat
a( | 152 BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::BitmapPlatformDeviceWinDat
a( |
154 HBITMAP hbitmap) | 153 HBITMAP hbitmap) |
155 : hbitmap_(hbitmap), | 154 : hbitmap_(hbitmap), |
156 hdc_(NULL), | 155 hdc_(NULL), |
157 config_dirty_(true) { // Want to load the config next time. | 156 config_dirty_(true) { // Want to load the config next time. |
158 // Initialize the clip region to the entire bitmap. | 157 // Initialize the clip region to the entire bitmap. |
159 BITMAP bitmap_data; | 158 BITMAP bitmap_data; |
160 if (GetObject(hbitmap_, sizeof(BITMAP), &bitmap_data)) { | 159 if (GetObject(hbitmap_, sizeof(BITMAP), &bitmap_data)) { |
(...skipping 22 matching lines...) Expand all Loading... |
183 // monochrome pixel wide and one monochrome pixel high. Since we select our | 182 // monochrome pixel wide and one monochrome pixel high. Since we select our |
184 // own bitmap, we must delete the previous one. | 183 // own bitmap, we must delete the previous one. |
185 DeleteObject(old_bitmap); | 184 DeleteObject(old_bitmap); |
186 } | 185 } |
187 | 186 |
188 LoadConfig(); | 187 LoadConfig(); |
189 return hdc_; | 188 return hdc_; |
190 } | 189 } |
191 | 190 |
192 void BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::ReleaseBitmapDC() { | 191 void BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::ReleaseBitmapDC() { |
193 DCHECK(hdc_); | 192 SkASSERT(hdc_); |
194 DeleteDC(hdc_); | 193 DeleteDC(hdc_); |
195 hdc_ = NULL; | 194 hdc_ = NULL; |
196 } | 195 } |
197 | 196 |
198 bool BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::IsBitmapDCCreated() | 197 bool BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::IsBitmapDCCreated() |
199 const { | 198 const { |
200 return hdc_ != NULL; | 199 return hdc_ != NULL; |
201 } | 200 } |
202 | 201 |
203 | 202 |
(...skipping 16 matching lines...) Expand all Loading... |
220 // We don't use transform_ for the clipping region since the translation is | 219 // We don't use transform_ for the clipping region since the translation is |
221 // already applied to offset_x_ and offset_y_. | 220 // already applied to offset_x_ and offset_y_. |
222 t.reset(); | 221 t.reset(); |
223 LoadClippingRegionToDC(hdc_, clip_region_, t); | 222 LoadClippingRegionToDC(hdc_, clip_region_, t); |
224 } | 223 } |
225 | 224 |
226 // We use this static factory function instead of the regular constructor so | 225 // We use this static factory function instead of the regular constructor so |
227 // that we can create the pixel data before calling the constructor. This is | 226 // that we can create the pixel data before calling the constructor. This is |
228 // required so that we can call the base class' constructor with the pixel | 227 // required so that we can call the base class' constructor with the pixel |
229 // data. | 228 // data. |
230 BitmapPlatformDeviceWin* BitmapPlatformDeviceWin::create(HDC screen_dc, | 229 BitmapPlatformDeviceWin* BitmapPlatformDeviceWin::create( |
231 int width, | 230 HDC screen_dc, |
232 int height, | 231 int width, |
233 bool is_opaque, | 232 int height, |
234 HANDLE shared_section) { | 233 bool is_opaque, |
| 234 HANDLE shared_section) { |
235 SkBitmap bitmap; | 235 SkBitmap bitmap; |
236 | 236 |
237 // CreateDIBSection appears to get unhappy if we create an empty bitmap, so | 237 // CreateDIBSection appears to get unhappy if we create an empty bitmap, so |
238 // just create a minimal bitmap | 238 // just create a minimal bitmap |
239 if ((width == 0) || (height == 0)) { | 239 if ((width == 0) || (height == 0)) { |
240 width = 1; | 240 width = 1; |
241 height = 1; | 241 height = 1; |
242 } | 242 } |
243 | 243 |
244 BITMAPINFOHEADER hdr = {0}; | 244 BITMAPINFOHEADER hdr = {0}; |
245 gfx::CreateBitmapHeader(width, height, &hdr); | 245 hdr.biSize = sizeof(BITMAPINFOHEADER); |
| 246 hdr.biWidth = width; |
| 247 hdr.biHeight = -height; // minus means top-down bitmap |
| 248 hdr.biPlanes = 1; |
| 249 hdr.biBitCount = 32; |
| 250 hdr.biCompression = BI_RGB; // no compression |
| 251 hdr.biSizeImage = 0; |
| 252 hdr.biXPelsPerMeter = 1; |
| 253 hdr.biYPelsPerMeter = 1; |
| 254 hdr.biClrUsed = 0; |
| 255 hdr.biClrImportant = 0; |
246 | 256 |
247 void* data = NULL; | 257 void* data = NULL; |
248 HBITMAP hbitmap = CreateDIBSection(screen_dc, | 258 HBITMAP hbitmap = CreateDIBSection(screen_dc, |
249 reinterpret_cast<BITMAPINFO*>(&hdr), 0, | 259 reinterpret_cast<BITMAPINFO*>(&hdr), 0, |
250 &data, | 260 &data, |
251 shared_section, 0); | 261 shared_section, 0); |
252 | 262 |
253 // If we run out of GDI objects or some other error occurs, we won't get a | 263 // If we run out of GDI objects or some other error occurs, we won't get a |
254 // bitmap here. This will cause us to crash later because the data pointer is | 264 // bitmap here. This will cause us to crash later because the data pointer is |
255 // NULL. To make sure that we can assign blame for those crashes to this code, | 265 // NULL. To make sure that we can assign blame for those crashes to this code, |
256 // we deliberately crash here, even in release mode. | 266 // we deliberately crash here, even in release mode. |
257 if (!hbitmap) { | 267 if (!hbitmap) { |
258 DWORD error = GetLastError(); | 268 DWORD error = GetLastError(); |
259 LOG(ERROR) << "CreateDIBSection Failed. Error: " << error << "\n"; | |
260 return NULL; | 269 return NULL; |
261 } | 270 } |
262 | 271 |
263 bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); | 272 bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); |
264 bitmap.setPixels(data); | 273 bitmap.setPixels(data); |
265 bitmap.setIsOpaque(is_opaque); | 274 bitmap.setIsOpaque(is_opaque); |
266 | 275 |
267 if (is_opaque) { | 276 if (is_opaque) { |
268 #ifndef NDEBUG | 277 #ifndef NDEBUG |
269 // To aid in finding bugs, we set the background color to something | 278 // To aid in finding bugs, we set the background color to something |
270 // obviously wrong so it will be noticable when it is not cleared | 279 // obviously wrong so it will be noticable when it is not cleared |
271 bitmap.eraseARGB(255, 0, 255, 128); // bright bluish green | 280 bitmap.eraseARGB(255, 0, 255, 128); // bright bluish green |
272 #endif | 281 #endif |
273 } else { | 282 } else { |
274 // A transparent layer is requested: fill with our magic "transparent" | 283 // A transparent layer is requested: fill with our magic "transparent" |
275 // color, see the declaration of kMagicTransparencyColor above | 284 // color, see the declaration of kMagicTransparencyColor above |
276 sk_memset32(static_cast<uint32_t*>(data), kMagicTransparencyColor, | 285 sk_memset32(static_cast<uint32_t*>(data), kMagicTransparencyColor, |
277 width * height); | 286 width * height); |
278 } | 287 } |
279 | 288 |
280 // The device object will take ownership of the HBITMAP. | 289 // The device object will take ownership of the HBITMAP. The initial refcount |
| 290 // of the data object will be 1, which is what the constructor expects. |
281 return new BitmapPlatformDeviceWin(new BitmapPlatformDeviceWinData(hbitmap), | 291 return new BitmapPlatformDeviceWin(new BitmapPlatformDeviceWinData(hbitmap), |
282 bitmap); | 292 bitmap); |
283 } | 293 } |
284 | 294 |
285 // The device will own the HBITMAP, which corresponds to also owning the pixel | 295 // The device will own the HBITMAP, which corresponds to also owning the pixel |
286 // data. Therefore, we do not transfer ownership to the SkDevice's bitmap. | 296 // data. Therefore, we do not transfer ownership to the SkDevice's bitmap. |
287 BitmapPlatformDeviceWin::BitmapPlatformDeviceWin( | 297 BitmapPlatformDeviceWin::BitmapPlatformDeviceWin( |
288 BitmapPlatformDeviceWinData* data, | 298 BitmapPlatformDeviceWinData* data, |
289 const SkBitmap& bitmap) : PlatformDeviceWin(bitmap), data_(data) { | 299 const SkBitmap& bitmap) |
| 300 : PlatformDeviceWin(bitmap), |
| 301 data_(data) { |
| 302 // The data object is already ref'ed for us by create(). |
290 } | 303 } |
291 | 304 |
292 // The copy constructor just adds another reference to the underlying data. | 305 // The copy constructor just adds another reference to the underlying data. |
293 // We use a const cast since the default Skia definitions don't define the | 306 // We use a const cast since the default Skia definitions don't define the |
294 // proper constedness that we expect (accessBitmap should really be const). | 307 // proper constedness that we expect (accessBitmap should really be const). |
295 BitmapPlatformDeviceWin::BitmapPlatformDeviceWin( | 308 BitmapPlatformDeviceWin::BitmapPlatformDeviceWin( |
296 const BitmapPlatformDeviceWin& other) | 309 const BitmapPlatformDeviceWin& other) |
297 : PlatformDeviceWin( | 310 : PlatformDeviceWin( |
298 const_cast<BitmapPlatformDeviceWin&>(other).accessBitmap(true)), | 311 const_cast<BitmapPlatformDeviceWin&>(other).accessBitmap(true)), |
299 data_(other.data_) { | 312 data_(other.data_) { |
| 313 data_->ref(); |
300 } | 314 } |
301 | 315 |
302 BitmapPlatformDeviceWin::~BitmapPlatformDeviceWin() { | 316 BitmapPlatformDeviceWin::~BitmapPlatformDeviceWin() { |
| 317 data_->unref(); |
303 } | 318 } |
304 | 319 |
305 BitmapPlatformDeviceWin& BitmapPlatformDeviceWin::operator=( | 320 BitmapPlatformDeviceWin& BitmapPlatformDeviceWin::operator=( |
306 const BitmapPlatformDeviceWin& other) { | 321 const BitmapPlatformDeviceWin& other) { |
307 data_ = other.data_; | 322 data_ = other.data_; |
| 323 data_->ref(); |
308 return *this; | 324 return *this; |
309 } | 325 } |
310 | 326 |
311 HDC BitmapPlatformDeviceWin::getBitmapDC() { | 327 HDC BitmapPlatformDeviceWin::getBitmapDC() { |
312 return data_->GetBitmapDC(); | 328 return data_->GetBitmapDC(); |
313 } | 329 } |
314 | 330 |
315 void BitmapPlatformDeviceWin::setMatrixClip(const SkMatrix& transform, | 331 void BitmapPlatformDeviceWin::setMatrixClip(const SkMatrix& transform, |
316 const SkRegion& region) { | 332 const SkRegion& region) { |
317 data_->SetMatrixClip(transform, region); | 333 data_->SetMatrixClip(transform, region); |
318 } | 334 } |
319 | 335 |
320 void BitmapPlatformDeviceWin::drawToHDC(HDC dc, int x, int y, | 336 void BitmapPlatformDeviceWin::drawToHDC(HDC dc, int x, int y, |
321 const RECT* src_rect) { | 337 const RECT* src_rect) { |
322 bool created_dc = !data_->IsBitmapDCCreated(); | 338 bool created_dc = !data_->IsBitmapDCCreated(); |
323 HDC source_dc = getBitmapDC(); | 339 HDC source_dc = getBitmapDC(); |
324 | 340 |
325 RECT temp_rect; | 341 RECT temp_rect; |
326 if (!src_rect) { | 342 if (!src_rect) { |
327 temp_rect.left = 0; | 343 temp_rect.left = 0; |
328 temp_rect.right = width(); | 344 temp_rect.right = width(); |
329 temp_rect.top = 0; | 345 temp_rect.top = 0; |
330 temp_rect.bottom = height(); | 346 temp_rect.bottom = height(); |
331 src_rect = &temp_rect; | 347 src_rect = &temp_rect; |
(...skipping 12 matching lines...) Expand all Loading... |
344 BitBlt(dc, | 360 BitBlt(dc, |
345 x, | 361 x, |
346 y, | 362 y, |
347 copy_width, | 363 copy_width, |
348 copy_height, | 364 copy_height, |
349 source_dc, | 365 source_dc, |
350 src_rect->left, | 366 src_rect->left, |
351 src_rect->top, | 367 src_rect->top, |
352 SRCCOPY); | 368 SRCCOPY); |
353 } else { | 369 } else { |
354 DCHECK(copy_width != 0 && copy_height != 0); | 370 SkASSERT(copy_width != 0 && copy_height != 0); |
355 BLENDFUNCTION blend_function = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; | 371 BLENDFUNCTION blend_function = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; |
356 GdiAlphaBlend(dc, | 372 GdiAlphaBlend(dc, |
357 x, | 373 x, |
358 y, | 374 y, |
359 copy_width, | 375 copy_width, |
360 copy_height, | 376 copy_height, |
361 source_dc, | 377 source_dc, |
362 src_rect->left, | 378 src_rect->left, |
363 src_rect->top, | 379 src_rect->top, |
364 copy_width, | 380 copy_width, |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
409 | 425 |
410 void BitmapPlatformDeviceWin::onAccessBitmap(SkBitmap* bitmap) { | 426 void BitmapPlatformDeviceWin::onAccessBitmap(SkBitmap* bitmap) { |
411 // FIXME(brettw) OPTIMIZATION: We should only flush if we know a GDI | 427 // FIXME(brettw) OPTIMIZATION: We should only flush if we know a GDI |
412 // operation has occurred on our DC. | 428 // operation has occurred on our DC. |
413 if (data_->IsBitmapDCCreated()) | 429 if (data_->IsBitmapDCCreated()) |
414 GdiFlush(); | 430 GdiFlush(); |
415 } | 431 } |
416 | 432 |
417 template<BitmapPlatformDeviceWin::adjustAlpha adjustor> | 433 template<BitmapPlatformDeviceWin::adjustAlpha adjustor> |
418 void BitmapPlatformDeviceWin::processPixels(int x, | 434 void BitmapPlatformDeviceWin::processPixels(int x, |
419 int y, | 435 int y, |
420 int width, | 436 int width, |
421 int height) { | 437 int height) { |
422 const SkBitmap& bitmap = accessBitmap(true); | 438 const SkBitmap& bitmap = accessBitmap(true); |
423 DCHECK_EQ(bitmap.config(), SkBitmap::kARGB_8888_Config); | 439 SkASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config); |
424 const SkMatrix& matrix = data_->transform(); | 440 const SkMatrix& matrix = data_->transform(); |
425 int bitmap_start_x = SkScalarRound(matrix.getTranslateX()) + x; | 441 int bitmap_start_x = SkScalarRound(matrix.getTranslateX()) + x; |
426 int bitmap_start_y = SkScalarRound(matrix.getTranslateY()) + y; | 442 int bitmap_start_y = SkScalarRound(matrix.getTranslateY()) + y; |
427 | 443 |
428 if (Constrain(bitmap.width(), &bitmap_start_x, &width) && | 444 if (Constrain(bitmap.width(), &bitmap_start_x, &width) && |
429 Constrain(bitmap.height(), &bitmap_start_y, &height)) { | 445 Constrain(bitmap.height(), &bitmap_start_y, &height)) { |
430 SkAutoLockPixels lock(bitmap); | 446 SkAutoLockPixels lock(bitmap); |
431 DCHECK_EQ(bitmap.rowBytes() % sizeof(uint32_t), 0u); | 447 SkASSERT(bitmap.rowBytes() % sizeof(uint32_t) == 0u); |
432 size_t row_words = bitmap.rowBytes() / sizeof(uint32_t); | 448 size_t row_words = bitmap.rowBytes() / sizeof(uint32_t); |
433 // Set data to the first pixel to be modified. | 449 // Set data to the first pixel to be modified. |
434 uint32_t* data = bitmap.getAddr32(0, 0) + (bitmap_start_y * row_words) + | 450 uint32_t* data = bitmap.getAddr32(0, 0) + (bitmap_start_y * row_words) + |
435 bitmap_start_x; | 451 bitmap_start_x; |
436 for (int i = 0; i < height; i++) { | 452 for (int i = 0; i < height; i++) { |
437 for (int j = 0; j < width; j++) { | 453 for (int j = 0; j < width; j++) { |
438 adjustor(data + j); | 454 adjustor(data + j); |
439 } | 455 } |
440 data += row_words; | 456 data += row_words; |
441 } | 457 } |
442 } | 458 } |
443 } | 459 } |
444 | 460 |
445 } // namespace skia | 461 } // namespace skia |
446 | 462 |
OLD | NEW |