| Index: base/gfx/bitmap_platform_device_win.cc
|
| ===================================================================
|
| --- base/gfx/bitmap_platform_device_win.cc (revision 5678)
|
| +++ base/gfx/bitmap_platform_device_win.cc (working copy)
|
| @@ -1,446 +0,0 @@
|
| -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "base/gfx/bitmap_platform_device_win.h"
|
| -
|
| -#include "base/gfx/gdi_util.h"
|
| -#include "base/logging.h"
|
| -#include "SkMatrix.h"
|
| -#include "SkRegion.h"
|
| -#include "SkUtils.h"
|
| -
|
| -namespace gfx {
|
| -
|
| -// When Windows draws text, is sets the fourth byte (which Skia uses for alpha)
|
| -// to zero. This means that if we try compositing with text that Windows has
|
| -// drawn, we get invalid color values (if the alpha is 0, the other channels
|
| -// should be 0 since Skia uses premultiplied colors) and strange results.
|
| -//
|
| -// HTML rendering only requires one bit of transparency. When you ask for a
|
| -// semitransparent div, the div itself is drawn in another layer as completely
|
| -// opaque, and then composited onto the lower layer with a transfer function.
|
| -// The only place an alpha channel is needed is to track what has been drawn
|
| -// and what has not been drawn.
|
| -//
|
| -// Therefore, when we allocate a new device, we fill it with this special
|
| -// color. Because Skia uses premultiplied colors, any color where the alpha
|
| -// channel is smaller than any component is impossible, so we know that no
|
| -// legitimate drawing will produce this color. We use 1 as the alpha value
|
| -// because 0 is produced when Windows draws text (even though it should be
|
| -// opaque).
|
| -//
|
| -// When a layer is done and we want to render it to a lower layer, we use
|
| -// fixupAlphaBeforeCompositing. This replaces all 0 alpha channels with
|
| -// opaque (to fix the text problem), and replaces this magic color value
|
| -// with transparency. The result is something that can be correctly
|
| -// composited. However, once this has been done, no more can be drawn to
|
| -// the layer because fixing the alphas *again* will result in incorrect
|
| -// values.
|
| -static const uint32_t kMagicTransparencyColor = 0x01FFFEFD;
|
| -
|
| -namespace {
|
| -
|
| -// Constrains position and size to fit within available_size. If |size| is -1,
|
| -// all the available_size is used. Returns false if the position is out of
|
| -// available_size.
|
| -bool Constrain(int available_size, int* position, int *size) {
|
| - if (*size < -2)
|
| - return false;
|
| -
|
| - if (*position < 0) {
|
| - if (*size != -1)
|
| - *size += *position;
|
| - *position = 0;
|
| - }
|
| - if (*size == 0 || *position >= available_size)
|
| - return false;
|
| -
|
| - if (*size > 0) {
|
| - int overflow = (*position + *size) - available_size;
|
| - if (overflow > 0) {
|
| - *size -= overflow;
|
| - }
|
| - } else {
|
| - // Fill up available size.
|
| - *size = available_size - *position;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -// If the pixel value is 0, it gets set to kMagicTransparencyColor.
|
| -void PrepareAlphaForGDI(uint32_t* pixel) {
|
| - if (*pixel == 0) {
|
| - *pixel = kMagicTransparencyColor;
|
| - }
|
| -}
|
| -
|
| -// If the pixel value is kMagicTransparencyColor, it gets set to 0. Otherwise
|
| -// if the alpha is 0, the alpha is set to 255.
|
| -void PostProcessAlphaForGDI(uint32_t* pixel) {
|
| - if (*pixel == kMagicTransparencyColor) {
|
| - *pixel = 0;
|
| - } else if ((*pixel & 0xFF000000) == 0) {
|
| - *pixel |= 0xFF000000;
|
| - }
|
| -}
|
| -
|
| -// Sets the opacity of the specified value to 0xFF.
|
| -void MakeOpaqueAlphaAdjuster(uint32_t* pixel) {
|
| - *pixel |= 0xFF000000;
|
| -}
|
| -
|
| -// See the declaration of kMagicTransparencyColor at the top of the file.
|
| -void FixupAlphaBeforeCompositing(uint32_t* pixel) {
|
| - if (*pixel == kMagicTransparencyColor)
|
| - *pixel = 0;
|
| - else
|
| - *pixel |= 0xFF000000;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -class BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData
|
| - : public base::RefCounted<BitmapPlatformDeviceWinData> {
|
| - public:
|
| - explicit BitmapPlatformDeviceWinData(HBITMAP hbitmap);
|
| -
|
| - // Create/destroy hdc_, which is the memory DC for our bitmap data.
|
| - HDC GetBitmapDC();
|
| - void ReleaseBitmapDC();
|
| - bool IsBitmapDCCreated() const;
|
| -
|
| - // Sets the transform and clip operations. This will not update the DC,
|
| - // but will mark the config as dirty. The next call of LoadConfig will
|
| - // pick up these changes.
|
| - void SetMatrixClip(const SkMatrix& transform, const SkRegion& region);
|
| -
|
| - const SkMatrix& transform() const {
|
| - return transform_;
|
| - }
|
| -
|
| - protected:
|
| - // Loads the current transform and clip into the DC. Can be called even when
|
| - // the DC is NULL (will be a NOP).
|
| - void LoadConfig();
|
| -
|
| - // Windows bitmap corresponding to our surface.
|
| - HBITMAP hbitmap_;
|
| -
|
| - // Lazily-created DC used to draw into the bitmap, see getBitmapDC.
|
| - HDC hdc_;
|
| -
|
| - // True when there is a transform or clip that has not been set to the DC.
|
| - // The DC is retrieved for every text operation, and the transform and clip
|
| - // do not change as much. We can save time by not loading the clip and
|
| - // transform for every one.
|
| - bool config_dirty_;
|
| -
|
| - // Translation assigned to the DC: we need to keep track of this separately
|
| - // so it can be updated even if the DC isn't created yet.
|
| - SkMatrix transform_;
|
| -
|
| - // The current clipping
|
| - SkRegion clip_region_;
|
| -
|
| - private:
|
| - friend class base::RefCounted<BitmapPlatformDeviceWinData>;
|
| - ~BitmapPlatformDeviceWinData();
|
| -
|
| - DISALLOW_EVIL_CONSTRUCTORS(BitmapPlatformDeviceWinData);
|
| -};
|
| -
|
| -BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::BitmapPlatformDeviceWinData(
|
| - HBITMAP hbitmap)
|
| - : hbitmap_(hbitmap),
|
| - hdc_(NULL),
|
| - config_dirty_(true) { // Want to load the config next time.
|
| - // Initialize the clip region to the entire bitmap.
|
| - BITMAP bitmap_data;
|
| - if (GetObject(hbitmap_, sizeof(BITMAP), &bitmap_data)) {
|
| - SkIRect rect;
|
| - rect.set(0, 0, bitmap_data.bmWidth, bitmap_data.bmHeight);
|
| - clip_region_ = SkRegion(rect);
|
| - }
|
| -
|
| - transform_.reset();
|
| -}
|
| -
|
| -BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::~BitmapPlatformDeviceWinData() {
|
| - if (hdc_)
|
| - ReleaseBitmapDC();
|
| -
|
| - // this will free the bitmap data as well as the bitmap handle
|
| - DeleteObject(hbitmap_);
|
| -}
|
| -
|
| -HDC BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::GetBitmapDC() {
|
| - if (!hdc_) {
|
| - hdc_ = CreateCompatibleDC(NULL);
|
| - InitializeDC(hdc_);
|
| - HGDIOBJ old_bitmap = SelectObject(hdc_, hbitmap_);
|
| - // When the memory DC is created, its display surface is exactly one
|
| - // monochrome pixel wide and one monochrome pixel high. Since we select our
|
| - // own bitmap, we must delete the previous one.
|
| - DeleteObject(old_bitmap);
|
| - }
|
| -
|
| - LoadConfig();
|
| - return hdc_;
|
| -}
|
| -
|
| -void BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::ReleaseBitmapDC() {
|
| - DCHECK(hdc_);
|
| - DeleteDC(hdc_);
|
| - hdc_ = NULL;
|
| -}
|
| -
|
| -bool BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::IsBitmapDCCreated()
|
| - const {
|
| - return hdc_ != NULL;
|
| -}
|
| -
|
| -
|
| -void BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::SetMatrixClip(
|
| - const SkMatrix& transform,
|
| - const SkRegion& region) {
|
| - transform_ = transform;
|
| - clip_region_ = region;
|
| - config_dirty_ = true;
|
| -}
|
| -
|
| -void BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData::LoadConfig() {
|
| - if (!config_dirty_ || !hdc_)
|
| - return; // Nothing to do.
|
| - config_dirty_ = false;
|
| -
|
| - // Transform.
|
| - SkMatrix t(transform_);
|
| - LoadTransformToDC(hdc_, t);
|
| - // We don't use transform_ for the clipping region since the translation is
|
| - // already applied to offset_x_ and offset_y_.
|
| - t.reset();
|
| - LoadClippingRegionToDC(hdc_, clip_region_, t);
|
| -}
|
| -
|
| -// We use this static factory function instead of the regular constructor so
|
| -// that we can create the pixel data before calling the constructor. This is
|
| -// required so that we can call the base class' constructor with the pixel
|
| -// data.
|
| -BitmapPlatformDeviceWin* BitmapPlatformDeviceWin::create(HDC screen_dc,
|
| - int width,
|
| - int height,
|
| - bool is_opaque,
|
| - HANDLE shared_section) {
|
| - SkBitmap bitmap;
|
| -
|
| - // CreateDIBSection appears to get unhappy if we create an empty bitmap, so
|
| - // just create a minimal bitmap
|
| - if ((width == 0) || (height == 0)) {
|
| - width = 1;
|
| - height = 1;
|
| - }
|
| -
|
| - BITMAPINFOHEADER hdr = {0};
|
| - CreateBitmapHeader(width, height, &hdr);
|
| -
|
| - void* data = NULL;
|
| - HBITMAP hbitmap = CreateDIBSection(screen_dc,
|
| - reinterpret_cast<BITMAPINFO*>(&hdr), 0,
|
| - &data,
|
| - shared_section, 0);
|
| -
|
| - // If we run out of GDI objects or some other error occurs, we won't get a
|
| - // bitmap here. This will cause us to crash later because the data pointer is
|
| - // NULL. To make sure that we can assign blame for those crashes to this code,
|
| - // we deliberately crash here, even in release mode.
|
| - if (!hbitmap) {
|
| - DWORD error = GetLastError();
|
| - LOG(ERROR) << "CreateDIBSection Failed. Error: " << error << "\n";
|
| - return NULL;
|
| - }
|
| -
|
| - bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
|
| - bitmap.setPixels(data);
|
| - bitmap.setIsOpaque(is_opaque);
|
| -
|
| - if (is_opaque) {
|
| -#ifndef NDEBUG
|
| - // To aid in finding bugs, we set the background color to something
|
| - // obviously wrong so it will be noticable when it is not cleared
|
| - bitmap.eraseARGB(255, 0, 255, 128); // bright bluish green
|
| -#endif
|
| - } else {
|
| - // A transparent layer is requested: fill with our magic "transparent"
|
| - // color, see the declaration of kMagicTransparencyColor above
|
| - sk_memset32(static_cast<uint32_t*>(data), kMagicTransparencyColor,
|
| - width * height);
|
| - }
|
| -
|
| - // The device object will take ownership of the HBITMAP.
|
| - return new BitmapPlatformDeviceWin(new BitmapPlatformDeviceWinData(hbitmap),
|
| - bitmap);
|
| -}
|
| -
|
| -// The device will own the HBITMAP, which corresponds to also owning the pixel
|
| -// data. Therefore, we do not transfer ownership to the SkDevice's bitmap.
|
| -BitmapPlatformDeviceWin::BitmapPlatformDeviceWin(
|
| - BitmapPlatformDeviceWinData* data,
|
| - const SkBitmap& bitmap) : PlatformDeviceWin(bitmap), data_(data) {
|
| -}
|
| -
|
| -// The copy constructor just adds another reference to the underlying data.
|
| -// We use a const cast since the default Skia definitions don't define the
|
| -// proper constedness that we expect (accessBitmap should really be const).
|
| -BitmapPlatformDeviceWin::BitmapPlatformDeviceWin(
|
| - const BitmapPlatformDeviceWin& other)
|
| - : PlatformDeviceWin(
|
| - const_cast<BitmapPlatformDeviceWin&>(other).accessBitmap(true)),
|
| - data_(other.data_) {
|
| -}
|
| -
|
| -BitmapPlatformDeviceWin::~BitmapPlatformDeviceWin() {
|
| -}
|
| -
|
| -BitmapPlatformDeviceWin& BitmapPlatformDeviceWin::operator=(
|
| - const BitmapPlatformDeviceWin& other) {
|
| - data_ = other.data_;
|
| - return *this;
|
| -}
|
| -
|
| -HDC BitmapPlatformDeviceWin::getBitmapDC() {
|
| - return data_->GetBitmapDC();
|
| -}
|
| -
|
| -void BitmapPlatformDeviceWin::setMatrixClip(const SkMatrix& transform,
|
| - const SkRegion& region) {
|
| - data_->SetMatrixClip(transform, region);
|
| -}
|
| -
|
| -void BitmapPlatformDeviceWin::drawToHDC(HDC dc, int x, int y,
|
| - const RECT* src_rect) {
|
| - bool created_dc = !data_->IsBitmapDCCreated();
|
| - HDC source_dc = getBitmapDC();
|
| -
|
| - RECT temp_rect;
|
| - if (!src_rect) {
|
| - temp_rect.left = 0;
|
| - temp_rect.right = width();
|
| - temp_rect.top = 0;
|
| - temp_rect.bottom = height();
|
| - src_rect = &temp_rect;
|
| - }
|
| -
|
| - int copy_width = src_rect->right - src_rect->left;
|
| - int copy_height = src_rect->bottom - src_rect->top;
|
| -
|
| - // We need to reset the translation for our bitmap or (0,0) won't be in the
|
| - // upper left anymore
|
| - SkMatrix identity;
|
| - identity.reset();
|
| -
|
| - LoadTransformToDC(source_dc, identity);
|
| - if (isOpaque()) {
|
| - BitBlt(dc,
|
| - x,
|
| - y,
|
| - copy_width,
|
| - copy_height,
|
| - source_dc,
|
| - src_rect->left,
|
| - src_rect->top,
|
| - SRCCOPY);
|
| - } else {
|
| - DCHECK(copy_width != 0 && copy_height != 0);
|
| - BLENDFUNCTION blend_function = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
|
| - GdiAlphaBlend(dc,
|
| - x,
|
| - y,
|
| - copy_width,
|
| - copy_height,
|
| - source_dc,
|
| - src_rect->left,
|
| - src_rect->top,
|
| - copy_width,
|
| - copy_height,
|
| - blend_function);
|
| - }
|
| - LoadTransformToDC(source_dc, data_->transform());
|
| -
|
| - if (created_dc)
|
| - data_->ReleaseBitmapDC();
|
| -}
|
| -
|
| -void BitmapPlatformDeviceWin::prepareForGDI(int x, int y, int width,
|
| - int height) {
|
| - processPixels<PrepareAlphaForGDI>(x, y, width, height);
|
| -}
|
| -
|
| -void BitmapPlatformDeviceWin::postProcessGDI(int x, int y, int width,
|
| - int height) {
|
| - processPixels<PostProcessAlphaForGDI>(x, y, width, height);
|
| -}
|
| -
|
| -void BitmapPlatformDeviceWin::makeOpaque(int x, int y, int width, int height) {
|
| - processPixels<MakeOpaqueAlphaAdjuster>(x, y, width, height);
|
| -}
|
| -
|
| -void BitmapPlatformDeviceWin::fixupAlphaBeforeCompositing() {
|
| - const SkBitmap& bitmap = accessBitmap(true);
|
| - SkAutoLockPixels lock(bitmap);
|
| - uint32_t* data = bitmap.getAddr32(0, 0);
|
| -
|
| - size_t words = bitmap.rowBytes() / sizeof(uint32_t) * bitmap.height();
|
| - for (size_t i = 0; i < words; i++) {
|
| - if (data[i] == kMagicTransparencyColor)
|
| - data[i] = 0;
|
| - else
|
| - data[i] |= 0xFF000000;
|
| - }
|
| -}
|
| -
|
| -// Returns the color value at the specified location.
|
| -SkColor BitmapPlatformDeviceWin::getColorAt(int x, int y) {
|
| - const SkBitmap& bitmap = accessBitmap(false);
|
| - SkAutoLockPixels lock(bitmap);
|
| - uint32_t* data = bitmap.getAddr32(0, 0);
|
| - return static_cast<SkColor>(data[x + y * width()]);
|
| -}
|
| -
|
| -void BitmapPlatformDeviceWin::onAccessBitmap(SkBitmap* bitmap) {
|
| - // FIXME(brettw) OPTIMIZATION: We should only flush if we know a GDI
|
| - // operation has occurred on our DC.
|
| - if (data_->IsBitmapDCCreated())
|
| - GdiFlush();
|
| -}
|
| -
|
| -template<BitmapPlatformDeviceWin::adjustAlpha adjustor>
|
| -void BitmapPlatformDeviceWin::processPixels(int x,
|
| - int y,
|
| - int width,
|
| - int height) {
|
| - const SkBitmap& bitmap = accessBitmap(true);
|
| - DCHECK_EQ(bitmap.config(), SkBitmap::kARGB_8888_Config);
|
| - const SkMatrix& matrix = data_->transform();
|
| - int bitmap_start_x = SkScalarRound(matrix.getTranslateX()) + x;
|
| - int bitmap_start_y = SkScalarRound(matrix.getTranslateY()) + y;
|
| -
|
| - if (Constrain(bitmap.width(), &bitmap_start_x, &width) &&
|
| - Constrain(bitmap.height(), &bitmap_start_y, &height)) {
|
| - SkAutoLockPixels lock(bitmap);
|
| - DCHECK_EQ(bitmap.rowBytes() % sizeof(uint32_t), 0u);
|
| - size_t row_words = bitmap.rowBytes() / sizeof(uint32_t);
|
| - // Set data to the first pixel to be modified.
|
| - uint32_t* data = bitmap.getAddr32(0, 0) + (bitmap_start_y * row_words) +
|
| - bitmap_start_x;
|
| - for (int i = 0; i < height; i++) {
|
| - for (int j = 0; j < width; j++) {
|
| - adjustor(data + j);
|
| - }
|
| - data += row_words;
|
| - }
|
| - }
|
| -}
|
| -
|
| -} // namespace gfx
|
| -
|
|
|