| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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 <windows.h> | |
| 6 #include <psapi.h> | |
| 7 #include <stddef.h> | |
| 8 | |
| 9 #include "base/debug/gdi_debug_util_win.h" | |
| 10 #include "base/logging.h" | |
| 11 #include "base/memory/ptr_util.h" | |
| 12 #include "base/win/win_util.h" | |
| 13 #include "skia/ext/bitmap_platform_device_win.h" | |
| 14 #include "skia/ext/platform_canvas.h" | |
| 15 #include "skia/ext/skia_utils_win.h" | |
| 16 #include "third_party/skia/include/core/SkMatrix.h" | |
| 17 #include "third_party/skia/include/core/SkPath.h" | |
| 18 #include "third_party/skia/include/core/SkRefCnt.h" | |
| 19 #include "third_party/skia/include/core/SkRect.h" | |
| 20 | |
| 21 namespace { | |
| 22 | |
| 23 void LoadClippingRegionToDC(HDC context, | |
| 24 const SkIRect& clip_bounds, | |
| 25 const SkMatrix& transformation) { | |
| 26 HRGN hrgn = CreateRectRgnIndirect(&skia::SkIRectToRECT(clip_bounds)); | |
| 27 int result = SelectClipRgn(context, hrgn); | |
| 28 SkASSERT(result != ERROR); | |
| 29 result = DeleteObject(hrgn); | |
| 30 SkASSERT(result != 0); | |
| 31 } | |
| 32 | |
| 33 } // namespace | |
| 34 | |
| 35 namespace skia { | |
| 36 | |
| 37 HDC GetNativeDrawingContext(SkCanvas* canvas) { | |
| 38 PlatformDevice* platform_device = GetPlatformDevice(canvas->getTopDevice(true)
); | |
| 39 if (!platform_device) | |
| 40 return nullptr; | |
| 41 | |
| 42 // Compensate for drawing to a layer rather than the entire canvas | |
| 43 SkMatrix ctm; | |
| 44 SkIRect clip_bounds; | |
| 45 canvas->temporary_internal_describeTopLayer(&ctm, &clip_bounds); | |
| 46 | |
| 47 return platform_device->BeginPlatformPaint(ctm, clip_bounds); | |
| 48 } | |
| 49 | |
| 50 HDC BitmapPlatformDevice::GetBitmapDC(const SkMatrix& transform, | |
| 51 const SkIRect& clip_bounds) { | |
| 52 if (!hdc_) { | |
| 53 hdc_ = CreateCompatibleDC(NULL); | |
| 54 InitializeDC(hdc_); | |
| 55 old_hbitmap_ = static_cast<HBITMAP>(SelectObject(hdc_, hbitmap_)); | |
| 56 } | |
| 57 | |
| 58 LoadConfig(transform, clip_bounds); | |
| 59 return hdc_; | |
| 60 } | |
| 61 | |
| 62 void BitmapPlatformDevice::ReleaseBitmapDC() { | |
| 63 SkASSERT(hdc_); | |
| 64 SelectObject(hdc_, old_hbitmap_); | |
| 65 DeleteDC(hdc_); | |
| 66 hdc_ = NULL; | |
| 67 old_hbitmap_ = NULL; | |
| 68 } | |
| 69 | |
| 70 bool BitmapPlatformDevice::IsBitmapDCCreated() | |
| 71 const { | |
| 72 return hdc_ != NULL; | |
| 73 } | |
| 74 | |
| 75 void BitmapPlatformDevice::LoadConfig(const SkMatrix& transform, | |
| 76 const SkIRect& clip_bounds) { | |
| 77 if (!hdc_) | |
| 78 return; // Nothing to do. | |
| 79 | |
| 80 // Transform. | |
| 81 skia::LoadTransformToDC(hdc_, transform); | |
| 82 LoadClippingRegionToDC(hdc_, clip_bounds, transform); | |
| 83 } | |
| 84 | |
| 85 static void DeleteHBitmapCallback(void* addr, void* context) { | |
| 86 // If context is not NULL then it's a valid HBITMAP to delete. | |
| 87 // Otherwise we just unmap the pixel memory. | |
| 88 if (context) | |
| 89 DeleteObject(static_cast<HBITMAP>(context)); | |
| 90 else | |
| 91 UnmapViewOfFile(addr); | |
| 92 } | |
| 93 | |
| 94 static bool InstallHBitmapPixels(SkBitmap* bitmap, int width, int height, | |
| 95 bool is_opaque, void* data, HBITMAP hbitmap) { | |
| 96 const SkAlphaType at = is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType; | |
| 97 const SkImageInfo info = SkImageInfo::MakeN32(width, height, at); | |
| 98 const size_t rowBytes = info.minRowBytes(); | |
| 99 SkColorTable* color_table = NULL; | |
| 100 return bitmap->installPixels(info, data, rowBytes, color_table, | |
| 101 DeleteHBitmapCallback, hbitmap); | |
| 102 } | |
| 103 | |
| 104 // We use this static factory function instead of the regular constructor so | |
| 105 // that we can create the pixel data before calling the constructor. This is | |
| 106 // required so that we can call the base class' constructor with the pixel | |
| 107 // data. | |
| 108 BitmapPlatformDevice* BitmapPlatformDevice::Create( | |
| 109 int width, | |
| 110 int height, | |
| 111 bool is_opaque, | |
| 112 HANDLE shared_section, | |
| 113 bool do_clear) { | |
| 114 | |
| 115 void* data; | |
| 116 HBITMAP hbitmap = NULL; | |
| 117 | |
| 118 // This function contains an implementation of a Skia platform bitmap for | |
| 119 // drawing and compositing graphics. The original implementation uses Windows | |
| 120 // GDI to create the backing bitmap memory, however it's possible for a | |
| 121 // process to not have access to GDI which will cause this code to fail. It's | |
| 122 // possible to detect when GDI is unavailable and instead directly map the | |
| 123 // shared memory as the bitmap. | |
| 124 if (base::win::IsUser32AndGdi32Available()) { | |
| 125 hbitmap = skia::CreateHBitmap(width, height, is_opaque, shared_section, | |
| 126 &data); | |
| 127 if (!hbitmap) { | |
| 128 LOG(ERROR) << "CreateHBitmap failed"; | |
| 129 return NULL; | |
| 130 } | |
| 131 } else { | |
| 132 DCHECK(shared_section != NULL); | |
| 133 data = MapViewOfFile(shared_section, FILE_MAP_WRITE, 0, 0, | |
| 134 PlatformCanvasStrideForWidth(width) * height); | |
| 135 if (!data) { | |
| 136 LOG(ERROR) << "MapViewOfFile failed"; | |
| 137 return NULL; | |
| 138 } | |
| 139 } | |
| 140 | |
| 141 SkBitmap bitmap; | |
| 142 if (!InstallHBitmapPixels(&bitmap, width, height, is_opaque, data, hbitmap)) { | |
| 143 LOG(ERROR) << "InstallHBitmapPixels failed"; | |
| 144 return NULL; | |
| 145 } | |
| 146 | |
| 147 if (do_clear) | |
| 148 bitmap.eraseColor(0); | |
| 149 | |
| 150 #ifndef NDEBUG | |
| 151 // If we were given data, then don't clobber it! | |
| 152 if (!shared_section && is_opaque) | |
| 153 // To aid in finding bugs, we set the background color to something | |
| 154 // obviously wrong so it will be noticable when it is not cleared | |
| 155 bitmap.eraseARGB(255, 0, 255, 128); // bright bluish green | |
| 156 #endif | |
| 157 | |
| 158 // The device object will take ownership of the HBITMAP. The initial refcount | |
| 159 // of the data object will be 1, which is what the constructor expects. | |
| 160 return new BitmapPlatformDevice(hbitmap, bitmap); | |
| 161 } | |
| 162 | |
| 163 // static | |
| 164 BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height, | |
| 165 bool is_opaque) { | |
| 166 const HANDLE shared_section = NULL; | |
| 167 const bool do_clear = false; | |
| 168 return Create(width, height, is_opaque, shared_section, do_clear); | |
| 169 } | |
| 170 | |
| 171 // The device will own the HBITMAP, which corresponds to also owning the pixel | |
| 172 // data. Therefore, we do not transfer ownership to the SkBitmapDevice's bitmap. | |
| 173 BitmapPlatformDevice::BitmapPlatformDevice( | |
| 174 HBITMAP hbitmap, | |
| 175 const SkBitmap& bitmap) | |
| 176 : SkBitmapDevice(bitmap), | |
| 177 hbitmap_(hbitmap), | |
| 178 old_hbitmap_(NULL), | |
| 179 hdc_(NULL) { | |
| 180 // The data object is already ref'ed for us by create(). | |
| 181 if (hbitmap) { | |
| 182 SetPlatformDevice(this, this); | |
| 183 BITMAP bitmap_data; | |
| 184 GetObject(hbitmap_, sizeof(BITMAP), &bitmap_data); | |
| 185 } | |
| 186 } | |
| 187 | |
| 188 BitmapPlatformDevice::~BitmapPlatformDevice() { | |
| 189 if (hdc_) | |
| 190 ReleaseBitmapDC(); | |
| 191 } | |
| 192 | |
| 193 HDC BitmapPlatformDevice::BeginPlatformPaint(const SkMatrix& transform, | |
| 194 const SkIRect& clip_bounds) { | |
| 195 return GetBitmapDC(transform, clip_bounds); | |
| 196 } | |
| 197 | |
| 198 SkBaseDevice* BitmapPlatformDevice::onCreateDevice(const CreateInfo& cinfo, | |
| 199 const SkPaint*) { | |
| 200 const SkImageInfo& info = cinfo.fInfo; | |
| 201 const bool do_clear = !info.isOpaque(); | |
| 202 SkASSERT(info.colorType() == kN32_SkColorType); | |
| 203 return Create(info.width(), info.height(), info.isOpaque(), NULL, do_clear); | |
| 204 } | |
| 205 | |
| 206 // PlatformCanvas impl | |
| 207 | |
| 208 std::unique_ptr<SkCanvas> CreatePlatformCanvasWithSharedSection( | |
| 209 int width, | |
| 210 int height, | |
| 211 bool is_opaque, | |
| 212 HANDLE shared_section, | |
| 213 OnFailureType failureType) { | |
| 214 sk_sp<SkBaseDevice> device( | |
| 215 BitmapPlatformDevice::Create(width, height, is_opaque, shared_section)); | |
| 216 if (!device) { | |
| 217 if (CRASH_ON_FAILURE == failureType) | |
| 218 SK_CRASH(); | |
| 219 return nullptr; | |
| 220 } | |
| 221 | |
| 222 return base::MakeUnique<SkCanvas>(device.get()); | |
| 223 } | |
| 224 | |
| 225 } // namespace skia | |
| OLD | NEW |