| 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 |