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 "SkMatrix.h" | 7 #include "SkMatrix.h" |
8 #include "SkRefCnt.h" | 8 #include "SkRefCnt.h" |
9 #include "SkRegion.h" | 9 #include "SkRegion.h" |
10 #include "SkUtils.h" | 10 #include "SkUtils.h" |
11 | 11 |
12 namespace skia { | 12 namespace skia { |
13 | 13 |
14 // When Windows draws text, is sets the fourth byte (which Skia uses for alpha) | |
15 // to zero. This means that if we try compositing with text that Windows has | |
16 // drawn, we get invalid color values (if the alpha is 0, the other channels | |
17 // should be 0 since Skia uses premultiplied colors) and strange results. | |
18 // | |
19 // HTML rendering only requires one bit of transparency. When you ask for a | |
20 // semitransparent div, the div itself is drawn in another layer as completely | |
21 // opaque, and then composited onto the lower layer with a transfer function. | |
22 // The only place an alpha channel is needed is to track what has been drawn | |
23 // and what has not been drawn. | |
24 // | |
25 // Therefore, when we allocate a new device, we fill it with this special | |
26 // color. Because Skia uses premultiplied colors, any color where the alpha | |
27 // channel is smaller than any component is impossible, so we know that no | |
28 // legitimate drawing will produce this color. We use 1 as the alpha value | |
29 // because 0 is produced when Windows draws text (even though it should be | |
30 // opaque). | |
31 // | |
32 // When a layer is done and we want to render it to a lower layer, we use | |
33 // fixupAlphaBeforeCompositing. This replaces all 0 alpha channels with | |
34 // opaque (to fix the text problem), and replaces this magic color value | |
35 // with transparency. The result is something that can be correctly | |
36 // composited. However, once this has been done, no more can be drawn to | |
37 // the layer because fixing the alphas *again* will result in incorrect | |
38 // values. | |
39 static const uint32_t kMagicTransparencyColor = 0x01FFFEFD; | |
40 | |
41 namespace { | 14 namespace { |
42 | 15 |
43 // Constrains position and size to fit within available_size. If |size| is -1, | 16 // Constrains position and size to fit within available_size. If |size| is -1, |
44 // all the available_size is used. Returns false if the position is out of | 17 // all the available_size is used. Returns false if the position is out of |
45 // available_size. | 18 // available_size. |
46 bool Constrain(int available_size, int* position, int *size) { | 19 bool Constrain(int available_size, int* position, int *size) { |
47 if (*size < -2) | 20 if (*size < -2) |
48 return false; | 21 return false; |
49 | 22 |
50 if (*position < 0) { | 23 if (*position < 0) { |
51 if (*size != -1) | 24 if (*size != -1) |
52 *size += *position; | 25 *size += *position; |
53 *position = 0; | 26 *position = 0; |
54 } | 27 } |
55 if (*size == 0 || *position >= available_size) | 28 if (*size == 0 || *position >= available_size) |
56 return false; | 29 return false; |
57 | 30 |
58 if (*size > 0) { | 31 if (*size > 0) { |
59 int overflow = (*position + *size) - available_size; | 32 int overflow = (*position + *size) - available_size; |
60 if (overflow > 0) { | 33 if (overflow > 0) { |
61 *size -= overflow; | 34 *size -= overflow; |
62 } | 35 } |
63 } else { | 36 } else { |
64 // Fill up available size. | 37 // Fill up available size. |
65 *size = available_size - *position; | 38 *size = available_size - *position; |
66 } | 39 } |
67 return true; | 40 return true; |
68 } | 41 } |
69 | 42 |
70 // If the pixel value is 0, it gets set to kMagicTransparencyColor. | |
71 void PrepareAlphaForGDI(uint32_t* pixel) { | |
72 if (*pixel == 0) { | |
73 *pixel = kMagicTransparencyColor; | |
74 } | |
75 } | |
76 | |
77 // If the pixel value is kMagicTransparencyColor, it gets set to 0. Otherwise | |
78 // if the alpha is 0, the alpha is set to 255. | |
79 void PostProcessAlphaForGDI(uint32_t* pixel) { | |
80 if (*pixel == kMagicTransparencyColor) { | |
81 *pixel = 0; | |
82 } else if ((*pixel & 0xFF000000) == 0) { | |
83 *pixel |= 0xFF000000; | |
84 } | |
85 } | |
86 | |
87 // Sets the opacity of the specified value to 0xFF. | |
88 void MakeOpaqueAlphaAdjuster(uint32_t* pixel) { | |
89 *pixel |= 0xFF000000; | |
90 } | |
91 | |
92 // See the declaration of kMagicTransparencyColor at the top of the file. | |
93 void FixupAlphaBeforeCompositing(uint32_t* pixel) { | |
94 if (*pixel == kMagicTransparencyColor) | |
95 *pixel = 0; | |
96 else | |
97 *pixel |= 0xFF000000; | |
98 } | |
99 | |
100 } // namespace | 43 } // namespace |
101 | 44 |
102 class BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData : public SkRefCnt { | 45 class BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData : public SkRefCnt { |
103 public: | 46 public: |
104 explicit BitmapPlatformDeviceWinData(HBITMAP hbitmap); | 47 explicit BitmapPlatformDeviceWinData(HBITMAP hbitmap); |
105 | 48 |
106 // Create/destroy hdc_, which is the memory DC for our bitmap data. | 49 // Create/destroy hdc_, which is the memory DC for our bitmap data. |
107 HDC GetBitmapDC(); | 50 HDC GetBitmapDC(); |
108 void ReleaseBitmapDC(); | 51 void ReleaseBitmapDC(); |
109 bool IsBitmapDCCreated() const; | 52 bool IsBitmapDCCreated() const; |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
273 bitmap.setPixels(data); | 216 bitmap.setPixels(data); |
274 bitmap.setIsOpaque(is_opaque); | 217 bitmap.setIsOpaque(is_opaque); |
275 | 218 |
276 if (is_opaque) { | 219 if (is_opaque) { |
277 #ifndef NDEBUG | 220 #ifndef NDEBUG |
278 // To aid in finding bugs, we set the background color to something | 221 // To aid in finding bugs, we set the background color to something |
279 // obviously wrong so it will be noticable when it is not cleared | 222 // obviously wrong so it will be noticable when it is not cleared |
280 bitmap.eraseARGB(255, 0, 255, 128); // bright bluish green | 223 bitmap.eraseARGB(255, 0, 255, 128); // bright bluish green |
281 #endif | 224 #endif |
282 } else { | 225 } else { |
283 // A transparent layer is requested: fill with our magic "transparent" | 226 bitmap.eraseARGB(0, 0, 0, 0); |
284 // color, see the declaration of kMagicTransparencyColor above | |
285 sk_memset32(static_cast<uint32_t*>(data), kMagicTransparencyColor, | |
286 width * height); | |
287 } | 227 } |
288 | 228 |
289 // The device object will take ownership of the HBITMAP. The initial refcount | 229 // 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. | 230 // of the data object will be 1, which is what the constructor expects. |
291 return new BitmapPlatformDeviceWin(new BitmapPlatformDeviceWinData(hbitmap), | 231 return new BitmapPlatformDeviceWin(new BitmapPlatformDeviceWinData(hbitmap), |
292 bitmap); | 232 bitmap); |
293 } | 233 } |
294 | 234 |
295 // The device will own the HBITMAP, which corresponds to also owning the pixel | 235 // The device will own the HBITMAP, which corresponds to also owning the pixel |
296 // data. Therefore, we do not transfer ownership to the SkDevice's bitmap. | 236 // data. Therefore, we do not transfer ownership to the SkDevice's bitmap. |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
380 copy_width, | 320 copy_width, |
381 copy_height, | 321 copy_height, |
382 blend_function); | 322 blend_function); |
383 } | 323 } |
384 LoadTransformToDC(source_dc, data_->transform()); | 324 LoadTransformToDC(source_dc, data_->transform()); |
385 | 325 |
386 if (created_dc) | 326 if (created_dc) |
387 data_->ReleaseBitmapDC(); | 327 data_->ReleaseBitmapDC(); |
388 } | 328 } |
389 | 329 |
390 void BitmapPlatformDeviceWin::prepareForGDI(int x, int y, int width, | |
391 int height) { | |
392 processPixels<PrepareAlphaForGDI>(x, y, width, height); | |
393 } | |
394 | |
395 void BitmapPlatformDeviceWin::postProcessGDI(int x, int y, int width, | |
396 int height) { | |
397 processPixels<PostProcessAlphaForGDI>(x, y, width, height); | |
398 } | |
399 | |
400 void BitmapPlatformDeviceWin::makeOpaque(int x, int y, int width, int height) { | 330 void BitmapPlatformDeviceWin::makeOpaque(int x, int y, int width, int height) { |
401 processPixels<MakeOpaqueAlphaAdjuster>(x, y, width, height); | |
402 } | |
403 | |
404 void BitmapPlatformDeviceWin::fixupAlphaBeforeCompositing() { | |
405 const SkBitmap& bitmap = accessBitmap(true); | |
406 SkAutoLockPixels lock(bitmap); | |
407 uint32_t* data = bitmap.getAddr32(0, 0); | |
408 | |
409 size_t words = bitmap.rowBytes() / sizeof(uint32_t) * bitmap.height(); | |
410 for (size_t i = 0; i < words; i++) { | |
411 if (data[i] == kMagicTransparencyColor) | |
412 data[i] = 0; | |
413 else | |
414 data[i] |= 0xFF000000; | |
415 } | |
416 } | |
417 | |
418 // Returns the color value at the specified location. | |
419 SkColor BitmapPlatformDeviceWin::getColorAt(int x, int y) { | |
420 const SkBitmap& bitmap = accessBitmap(false); | |
421 SkAutoLockPixels lock(bitmap); | |
422 uint32_t* data = bitmap.getAddr32(0, 0); | |
423 return static_cast<SkColor>(data[x + y * width()]); | |
424 } | |
425 | |
426 void BitmapPlatformDeviceWin::onAccessBitmap(SkBitmap* bitmap) { | |
427 // FIXME(brettw) OPTIMIZATION: We should only flush if we know a GDI | |
428 // operation has occurred on our DC. | |
429 if (data_->IsBitmapDCCreated()) | |
430 GdiFlush(); | |
431 } | |
432 | |
433 template<BitmapPlatformDeviceWin::adjustAlpha adjustor> | |
434 void BitmapPlatformDeviceWin::processPixels(int x, | |
435 int y, | |
436 int width, | |
437 int height) { | |
438 const SkBitmap& bitmap = accessBitmap(true); | 331 const SkBitmap& bitmap = accessBitmap(true); |
439 SkASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config); | 332 SkASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config); |
| 333 |
| 334 // FIXME(brettw): This is kind of lame, we shouldn't be dealing with |
| 335 // transforms at this level. Probably there should be a PlatformCanvas |
| 336 // function that does the transform (using the actual transform not just the |
| 337 // translation) and calls us with the transformed rect. |
440 const SkMatrix& matrix = data_->transform(); | 338 const SkMatrix& matrix = data_->transform(); |
441 int bitmap_start_x = SkScalarRound(matrix.getTranslateX()) + x; | 339 int bitmap_start_x = SkScalarRound(matrix.getTranslateX()) + x; |
442 int bitmap_start_y = SkScalarRound(matrix.getTranslateY()) + y; | 340 int bitmap_start_y = SkScalarRound(matrix.getTranslateY()) + y; |
443 | 341 |
444 if (Constrain(bitmap.width(), &bitmap_start_x, &width) && | 342 if (Constrain(bitmap.width(), &bitmap_start_x, &width) && |
445 Constrain(bitmap.height(), &bitmap_start_y, &height)) { | 343 Constrain(bitmap.height(), &bitmap_start_y, &height)) { |
446 SkAutoLockPixels lock(bitmap); | 344 SkAutoLockPixels lock(bitmap); |
447 SkASSERT(bitmap.rowBytes() % sizeof(uint32_t) == 0u); | 345 SkASSERT(bitmap.rowBytes() % sizeof(uint32_t) == 0u); |
448 size_t row_words = bitmap.rowBytes() / sizeof(uint32_t); | 346 size_t row_words = bitmap.rowBytes() / sizeof(uint32_t); |
449 // Set data to the first pixel to be modified. | 347 // Set data to the first pixel to be modified. |
450 uint32_t* data = bitmap.getAddr32(0, 0) + (bitmap_start_y * row_words) + | 348 uint32_t* data = bitmap.getAddr32(0, 0) + (bitmap_start_y * row_words) + |
451 bitmap_start_x; | 349 bitmap_start_x; |
452 for (int i = 0; i < height; i++) { | 350 for (int i = 0; i < height; i++) { |
453 for (int j = 0; j < width; j++) { | 351 for (int j = 0; j < width; j++) |
454 adjustor(data + j); | 352 data[j] |= (0xFF << SK_A32_SHIFT); |
455 } | |
456 data += row_words; | 353 data += row_words; |
457 } | 354 } |
458 } | 355 } |
459 } | 356 } |
460 | 357 |
| 358 // Returns the color value at the specified location. |
| 359 SkColor BitmapPlatformDeviceWin::getColorAt(int x, int y) { |
| 360 const SkBitmap& bitmap = accessBitmap(false); |
| 361 SkAutoLockPixels lock(bitmap); |
| 362 uint32_t* data = bitmap.getAddr32(0, 0); |
| 363 return static_cast<SkColor>(data[x + y * width()]); |
| 364 } |
| 365 |
| 366 void BitmapPlatformDeviceWin::onAccessBitmap(SkBitmap* bitmap) { |
| 367 // FIXME(brettw) OPTIMIZATION: We should only flush if we know a GDI |
| 368 // operation has occurred on our DC. |
| 369 if (data_->IsBitmapDCCreated()) |
| 370 GdiFlush(); |
| 371 } |
| 372 |
461 } // namespace skia | 373 } // namespace skia |
462 | 374 |
OLD | NEW |