| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2009 Google Inc. All rights reserved. | |
| 3 * | |
| 4 * Redistribution and use in source and binary forms, with or without | |
| 5 * modification, are permitted provided that the following conditions are | |
| 6 * met: | |
| 7 * | |
| 8 * * Redistributions of source code must retain the above copyright | |
| 9 * notice, this list of conditions and the following disclaimer. | |
| 10 * * Redistributions in binary form must reproduce the above | |
| 11 * copyright notice, this list of conditions and the following disclaimer | |
| 12 * in the documentation and/or other materials provided with the | |
| 13 * distribution. | |
| 14 * * Neither the name of Google Inc. nor the names of its | |
| 15 * contributors may be used to endorse or promote products derived from | |
| 16 * this software without specific prior written permission. | |
| 17 * | |
| 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 29 */ | |
| 30 | |
| 31 #include <windows.h> | |
| 32 #include "config.h" | |
| 33 | |
| 34 #include "core/platform/graphics/GraphicsContext.h" | |
| 35 #include "core/platform/graphics/ImageBuffer.h" | |
| 36 #include "core/platform/graphics/SimpleFontData.h" | |
| 37 #include "core/platform/graphics/chromium/TransparencyWin.h" | |
| 38 #include "core/platform/graphics/skia/SkiaUtils.h" | |
| 39 #include "platform/transforms/AffineTransform.h" | |
| 40 | |
| 41 #include "SkColorPriv.h" | |
| 42 #include "skia/ext/platform_canvas.h" | |
| 43 | |
| 44 namespace WebCore { | |
| 45 | |
| 46 namespace { | |
| 47 | |
| 48 // The maximum size in pixels of the buffer we'll keep around for drawing text | |
| 49 // into. Buffers larger than this will be destroyed when we're done with them. | |
| 50 const int maxCachedBufferPixelSize = 65536; | |
| 51 | |
| 52 inline const SkBitmap& bitmapForContext(const GraphicsContext& context) | |
| 53 { | |
| 54 return context.layerBitmap(); | |
| 55 } | |
| 56 | |
| 57 void compositeToCopy(GraphicsContext& sourceLayers, | |
| 58 GraphicsContext& destContext, | |
| 59 const AffineTransform& matrix) | |
| 60 { | |
| 61 // Make a list of all devices. The iterator goes top-down, and we want | |
| 62 // bottom-up. Note that each layer can also have an offset in canvas | |
| 63 // coordinates, which is the (x, y) position. | |
| 64 struct DeviceInfo { | |
| 65 DeviceInfo(SkBaseDevice* d, int lx, int ly) | |
| 66 : device(d) | |
| 67 , x(lx) | |
| 68 , y(ly) {} | |
| 69 SkBaseDevice* device; | |
| 70 int x; | |
| 71 int y; | |
| 72 }; | |
| 73 Vector<DeviceInfo> devices; | |
| 74 SkCanvas* sourceCanvas = sourceLayers.canvas(); | |
| 75 SkCanvas::LayerIter iter(sourceCanvas, false); | |
| 76 while (!iter.done()) { | |
| 77 devices.append(DeviceInfo(iter.device(), iter.x(), iter.y())); | |
| 78 iter.next(); | |
| 79 } | |
| 80 | |
| 81 // Create a temporary canvas for the compositing into the destination. | |
| 82 SkBitmap* destBmp = const_cast<SkBitmap*>(&bitmapForContext(destContext)); | |
| 83 SkCanvas destCanvas(*destBmp); | |
| 84 destCanvas.setMatrix(affineTransformToSkMatrix(matrix)); | |
| 85 | |
| 86 for (int i = devices.size() - 1; i >= 0; i--) { | |
| 87 const SkBitmap& srcBmp = devices[i].device->accessBitmap(false); | |
| 88 | |
| 89 SkRect destRect; | |
| 90 destRect.fLeft = devices[i].x; | |
| 91 destRect.fTop = devices[i].y; | |
| 92 destRect.fRight = destRect.fLeft + srcBmp.width(); | |
| 93 destRect.fBottom = destRect.fTop + srcBmp.height(); | |
| 94 | |
| 95 destCanvas.drawBitmapRect(srcBmp, 0, destRect); | |
| 96 } | |
| 97 } | |
| 98 | |
| 99 } // namespace | |
| 100 | |
| 101 // If either of these pointers is non-null, both must be valid and point to | |
| 102 // bitmaps of the same size. | |
| 103 class TransparencyWin::OwnedBuffers { | |
| 104 public: | |
| 105 OwnedBuffers(const IntSize& size, bool needReferenceBuffer) | |
| 106 { | |
| 107 m_destBitmap = ImageBuffer::create(size, 1); | |
| 108 | |
| 109 if (needReferenceBuffer) { | |
| 110 m_referenceBitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(
), size.height()); | |
| 111 m_referenceBitmap.allocPixels(); | |
| 112 m_referenceBitmap.eraseARGB(0, 0, 0, 0); | |
| 113 } | |
| 114 } | |
| 115 | |
| 116 ImageBuffer* destBitmap() { return m_destBitmap.get(); } | |
| 117 | |
| 118 // This bitmap will be empty if you don't specify needReferenceBuffer to the | |
| 119 // constructor. | |
| 120 SkBitmap* referenceBitmap() { return &m_referenceBitmap; } | |
| 121 | |
| 122 // Returns whether the current layer will fix a buffer of the given size. | |
| 123 bool canHandleSize(const IntSize& size) const | |
| 124 { | |
| 125 return m_destBitmap->internalSize().width() >= size.width() && m_destBit
map->internalSize().height() >= size.height(); | |
| 126 } | |
| 127 | |
| 128 private: | |
| 129 // The destination bitmap we're drawing into. | |
| 130 OwnPtr<ImageBuffer> m_destBitmap; | |
| 131 | |
| 132 // This could be an ImageBuffer but this is an optimization. Since this is | |
| 133 // only ever used as a reference, we don't need to make a full | |
| 134 // PlatformCanvas using Skia on Windows. Just allocating a regular SkBitmap | |
| 135 // is much faster since it's just a Malloc rather than a GDI call. | |
| 136 SkBitmap m_referenceBitmap; | |
| 137 }; | |
| 138 | |
| 139 TransparencyWin::OwnedBuffers* TransparencyWin::m_cachedBuffers = 0; | |
| 140 | |
| 141 TransparencyWin::TransparencyWin() | |
| 142 : m_destContext(0) | |
| 143 , m_orgTransform() | |
| 144 , m_layerMode(NoLayer) | |
| 145 , m_transformMode(KeepTransform) | |
| 146 , m_drawContext(0) | |
| 147 , m_savedOnDrawContext(false) | |
| 148 , m_layerBuffer(0) | |
| 149 , m_referenceBitmap(0) | |
| 150 , m_validLayer(false) | |
| 151 { | |
| 152 } | |
| 153 | |
| 154 TransparencyWin::~TransparencyWin() | |
| 155 { | |
| 156 // This should be false, since calling composite() is mandatory. | |
| 157 ASSERT(!m_savedOnDrawContext); | |
| 158 } | |
| 159 | |
| 160 void TransparencyWin::composite() | |
| 161 { | |
| 162 // Matches the save() in initializeNewTextContext (or the constructor for | |
| 163 // SCALE) to put the context back into the same state we found it. | |
| 164 if (m_savedOnDrawContext) { | |
| 165 m_drawContext->restore(); | |
| 166 m_savedOnDrawContext = false; | |
| 167 } | |
| 168 | |
| 169 switch (m_layerMode) { | |
| 170 case NoLayer: | |
| 171 break; | |
| 172 case OpaqueCompositeLayer: | |
| 173 case WhiteLayer: | |
| 174 compositeOpaqueComposite(); | |
| 175 break; | |
| 176 case TextComposite: | |
| 177 compositeTextComposite(); | |
| 178 break; | |
| 179 } | |
| 180 } | |
| 181 | |
| 182 void TransparencyWin::init(GraphicsContext* dest, | |
| 183 LayerMode layerMode, | |
| 184 TransformMode transformMode, | |
| 185 const IntRect& region) | |
| 186 { | |
| 187 m_destContext = dest; | |
| 188 m_orgTransform = dest->getCTM(); | |
| 189 m_layerMode = layerMode; | |
| 190 m_transformMode = transformMode; | |
| 191 m_sourceRect = region; | |
| 192 | |
| 193 computeLayerSize(); | |
| 194 setupLayer(); | |
| 195 setupTransform(region); | |
| 196 } | |
| 197 | |
| 198 void TransparencyWin::computeLayerSize() | |
| 199 { | |
| 200 if (m_transformMode == Untransform) { | |
| 201 // The meaning of the "transformed" source rect is a little ambigous | |
| 202 // here. The rest of the code doesn't care about it in the Untransform | |
| 203 // case since we're using our own happy coordinate system. So we set it | |
| 204 // to be the source rect since that matches how the code below actually | |
| 205 // uses the variable: to determine how to translate things to account | |
| 206 // for the offset of the layer. | |
| 207 m_transformedSourceRect = m_sourceRect; | |
| 208 } else if (m_transformMode == KeepTransform && m_layerMode != TextComposite)
{ | |
| 209 // FIXME: support clipping for other modes | |
| 210 IntRect clippedSourceRect = m_sourceRect; | |
| 211 SkRect clipBounds; | |
| 212 if (m_destContext->getClipBounds(&clipBounds)) { | |
| 213 FloatRect clipRect(clipBounds.left(), clipBounds.top(), clipBounds.w
idth(), clipBounds.height()); | |
| 214 clippedSourceRect.intersect(enclosingIntRect(clipRect)); | |
| 215 } | |
| 216 m_transformedSourceRect = m_orgTransform.mapRect(clippedSourceRect); | |
| 217 } else | |
| 218 m_transformedSourceRect = m_orgTransform.mapRect(m_sourceRect); | |
| 219 | |
| 220 m_layerSize = IntSize(m_transformedSourceRect.width(), m_transformedSourceRe
ct.height()); | |
| 221 } | |
| 222 | |
| 223 void TransparencyWin::setupLayer() | |
| 224 { | |
| 225 switch (m_layerMode) { | |
| 226 case NoLayer: | |
| 227 setupLayerForNoLayer(); | |
| 228 break; | |
| 229 case OpaqueCompositeLayer: | |
| 230 setupLayerForOpaqueCompositeLayer(); | |
| 231 break; | |
| 232 case TextComposite: | |
| 233 setupLayerForTextComposite(); | |
| 234 break; | |
| 235 case WhiteLayer: | |
| 236 setupLayerForWhiteLayer(); | |
| 237 break; | |
| 238 } | |
| 239 } | |
| 240 | |
| 241 void TransparencyWin::setupLayerForNoLayer() | |
| 242 { | |
| 243 m_drawContext = m_destContext; // Draw to the source context. | |
| 244 m_validLayer = true; | |
| 245 } | |
| 246 | |
| 247 void TransparencyWin::setupLayerForOpaqueCompositeLayer() | |
| 248 { | |
| 249 initializeNewContext(); | |
| 250 if (!m_validLayer) | |
| 251 return; | |
| 252 | |
| 253 AffineTransform mapping; | |
| 254 mapping.translate(-m_transformedSourceRect.x(), -m_transformedSourceRect.y()
); | |
| 255 if (m_transformMode == Untransform){ | |
| 256 // Compute the inverse mapping from the canvas space to the | |
| 257 // coordinate space of our bitmap. | |
| 258 mapping *= m_orgTransform.inverse(); | |
| 259 } | |
| 260 compositeToCopy(*m_destContext, *m_drawContext, mapping); | |
| 261 | |
| 262 // Save the reference layer so we can tell what changed. | |
| 263 SkCanvas referenceCanvas(*m_referenceBitmap); | |
| 264 referenceCanvas.drawBitmap(bitmapForContext(*m_drawContext), 0, 0); | |
| 265 // Layer rect represents the part of the original layer. | |
| 266 } | |
| 267 | |
| 268 void TransparencyWin::setupLayerForTextComposite() | |
| 269 { | |
| 270 ASSERT(m_transformMode == KeepTransform); | |
| 271 // Fall through to filling with white. | |
| 272 setupLayerForWhiteLayer(); | |
| 273 } | |
| 274 | |
| 275 void TransparencyWin::setupLayerForWhiteLayer() | |
| 276 { | |
| 277 initializeNewContext(); | |
| 278 if (!m_validLayer) | |
| 279 return; | |
| 280 | |
| 281 m_drawContext->fillRect(IntRect(IntPoint(0, 0), m_layerSize), Color::white); | |
| 282 // Layer rect represents the part of the original layer. | |
| 283 } | |
| 284 | |
| 285 void TransparencyWin::setupTransform(const IntRect& region) | |
| 286 { | |
| 287 switch (m_transformMode) { | |
| 288 case KeepTransform: | |
| 289 setupTransformForKeepTransform(region); | |
| 290 break; | |
| 291 case Untransform: | |
| 292 setupTransformForUntransform(); | |
| 293 break; | |
| 294 case ScaleTransform: | |
| 295 setupTransformForScaleTransform(); | |
| 296 break; | |
| 297 } | |
| 298 } | |
| 299 | |
| 300 void TransparencyWin::setupTransformForKeepTransform(const IntRect& region) | |
| 301 { | |
| 302 if (!m_validLayer) | |
| 303 return; | |
| 304 | |
| 305 if (m_layerMode != NoLayer) { | |
| 306 // Need to save things since we're modifying the transform. | |
| 307 m_drawContext->save(); | |
| 308 m_savedOnDrawContext = true; | |
| 309 | |
| 310 // Account for the fact that the layer may be offset from the | |
| 311 // original. This only happens when we create a layer that has the | |
| 312 // same coordinate space as the parent. | |
| 313 AffineTransform xform; | |
| 314 xform.translate(-m_transformedSourceRect.x(), -m_transformedSourceRect.y
()); | |
| 315 | |
| 316 // We're making a layer, so apply the old transform to the new one | |
| 317 // so it's maintained. We know the new layer has the identity | |
| 318 // transform now, we we can just multiply it. | |
| 319 xform *= m_orgTransform; | |
| 320 m_drawContext->concatCTM(xform); | |
| 321 } | |
| 322 m_drawRect = m_sourceRect; | |
| 323 } | |
| 324 | |
| 325 void TransparencyWin::setupTransformForUntransform() | |
| 326 { | |
| 327 ASSERT(m_layerMode != NoLayer); | |
| 328 // We now have a new layer with the identity transform, which is the | |
| 329 // Untransformed space we'll use for drawing. | |
| 330 m_drawRect = IntRect(IntPoint(0, 0), m_layerSize); | |
| 331 } | |
| 332 | |
| 333 void TransparencyWin::setupTransformForScaleTransform() | |
| 334 { | |
| 335 if (!m_validLayer) | |
| 336 return; | |
| 337 | |
| 338 if (m_layerMode == NoLayer) { | |
| 339 // Need to save things since we're modifying the layer. | |
| 340 m_drawContext->save(); | |
| 341 m_savedOnDrawContext = true; | |
| 342 | |
| 343 // Undo the transform on the current layer when we're re-using the | |
| 344 // current one. | |
| 345 m_drawContext->concatCTM(m_drawContext->getCTM().inverse()); | |
| 346 | |
| 347 // We're drawing to the original layer with just a different size. | |
| 348 m_drawRect = m_transformedSourceRect; | |
| 349 } else { | |
| 350 // Just go ahead and use the layer's coordinate space to draw into. | |
| 351 // It will have the scaled size, and an identity transform loaded. | |
| 352 m_drawRect = IntRect(IntPoint(0, 0), m_layerSize); | |
| 353 } | |
| 354 } | |
| 355 | |
| 356 void TransparencyWin::setTextCompositeColor(Color color) | |
| 357 { | |
| 358 m_textCompositeColor = color; | |
| 359 } | |
| 360 | |
| 361 void TransparencyWin::initializeNewContext() | |
| 362 { | |
| 363 int pixelSize = m_layerSize.width() * m_layerSize.height(); | |
| 364 if (pixelSize <= 0) | |
| 365 return; | |
| 366 | |
| 367 if (pixelSize > maxCachedBufferPixelSize) { | |
| 368 // Create a 1-off buffer for drawing into. We only need the reference | |
| 369 // buffer if we're making an OpaqueCompositeLayer. | |
| 370 bool needReferenceBitmap = m_layerMode == OpaqueCompositeLayer; | |
| 371 m_ownedBuffers = adoptPtr(new OwnedBuffers(m_layerSize, needReferenceBit
map)); | |
| 372 m_layerBuffer = m_ownedBuffers->destBitmap(); | |
| 373 if (!m_layerBuffer) | |
| 374 return; | |
| 375 | |
| 376 m_drawContext = m_layerBuffer->context(); | |
| 377 if (needReferenceBitmap) { | |
| 378 m_referenceBitmap = m_ownedBuffers->referenceBitmap(); | |
| 379 if (!m_referenceBitmap || !m_referenceBitmap->getPixels()) | |
| 380 return; | |
| 381 } | |
| 382 m_validLayer = true; | |
| 383 return; | |
| 384 } | |
| 385 | |
| 386 if (m_cachedBuffers && m_cachedBuffers->canHandleSize(m_layerSize)) { | |
| 387 // We can re-use the existing buffer. We don't need to clear it since | |
| 388 // all layer modes will clear it in their initialization. | |
| 389 m_layerBuffer = m_cachedBuffers->destBitmap(); | |
| 390 m_drawContext = m_cachedBuffers->destBitmap()->context(); | |
| 391 bitmapForContext(*m_drawContext).eraseARGB(0, 0, 0, 0); | |
| 392 m_referenceBitmap = m_cachedBuffers->referenceBitmap(); | |
| 393 m_referenceBitmap->eraseARGB(0, 0, 0, 0); | |
| 394 m_validLayer = true; | |
| 395 return; | |
| 396 } | |
| 397 | |
| 398 // Create a new cached buffer. | |
| 399 if (m_cachedBuffers) | |
| 400 delete m_cachedBuffers; | |
| 401 m_cachedBuffers = new OwnedBuffers(m_layerSize, true); | |
| 402 | |
| 403 m_layerBuffer = m_cachedBuffers->destBitmap(); | |
| 404 m_drawContext = m_cachedBuffers->destBitmap()->context(); | |
| 405 m_referenceBitmap = m_cachedBuffers->referenceBitmap(); | |
| 406 m_validLayer = true; | |
| 407 } | |
| 408 | |
| 409 void TransparencyWin::compositeOpaqueComposite() | |
| 410 { | |
| 411 if (!m_validLayer) | |
| 412 return; | |
| 413 | |
| 414 m_destContext->save(); | |
| 415 | |
| 416 SkBitmap* bitmap = const_cast<SkBitmap*>( | |
| 417 &bitmapForContext(*m_layerBuffer->context())); | |
| 418 | |
| 419 // This function will be called for WhiteLayer as well, which we don't want | |
| 420 // to change. | |
| 421 if (m_layerMode == OpaqueCompositeLayer) { | |
| 422 // Fix up our bitmap, making it contain only the pixels which changed | |
| 423 // and transparent everywhere else. | |
| 424 SkAutoLockPixels sourceLock(*m_referenceBitmap); | |
| 425 SkAutoLockPixels lock(*bitmap); | |
| 426 for (int y = 0; y < bitmap->height(); y++) { | |
| 427 uint32_t* source = m_referenceBitmap->getAddr32(0, y); | |
| 428 uint32_t* dest = bitmap->getAddr32(0, y); | |
| 429 for (int x = 0; x < bitmap->width(); x++) { | |
| 430 // Clear out any pixels that were untouched. | |
| 431 if (dest[x] == source[x]) | |
| 432 dest[x] = 0; | |
| 433 else | |
| 434 dest[x] |= (0xFF << SK_A32_SHIFT); | |
| 435 } | |
| 436 } | |
| 437 } else | |
| 438 makeLayerOpaque(); | |
| 439 | |
| 440 SkRect destRect; | |
| 441 if (m_transformMode != Untransform) { | |
| 442 // We want to use Untransformed space. | |
| 443 // | |
| 444 // Note that we DON'T call m_layerBuffer->image() here. This actually | |
| 445 // makes a copy of the image, which is unnecessary and slow. Instead, we | |
| 446 // just draw the image from inside the destination context. | |
| 447 SkMatrix identity; | |
| 448 identity.reset(); | |
| 449 m_destContext->setMatrix(identity); | |
| 450 | |
| 451 destRect.set(m_transformedSourceRect.x(), m_transformedSourceRect.y(), m
_transformedSourceRect.maxX(), m_transformedSourceRect.maxY()); | |
| 452 } else | |
| 453 destRect.set(m_sourceRect.x(), m_sourceRect.y(), m_sourceRect.maxX(), m_
sourceRect.maxY()); | |
| 454 | |
| 455 SkPaint paint; | |
| 456 paint.setFilterBitmap(true); | |
| 457 paint.setAntiAlias(true); | |
| 458 | |
| 459 // Note that we need to specify the source layer subset, since the bitmap | |
| 460 // may have been cached and it could be larger than what we're using. | |
| 461 SkRect sourceRect = SkRect::MakeWH( | |
| 462 SkIntToScalar(m_layerSize.width()), | |
| 463 SkIntToScalar(m_layerSize.height())); | |
| 464 m_destContext->drawBitmapRect(*bitmap, &sourceRect, destRect, &paint); | |
| 465 m_destContext->restore(); | |
| 466 } | |
| 467 | |
| 468 void TransparencyWin::compositeTextComposite() | |
| 469 { | |
| 470 if (!m_validLayer) | |
| 471 return; | |
| 472 | |
| 473 const SkBitmap& bitmap = m_layerBuffer->context()->layerBitmap(GraphicsConte
xt::ReadWrite); | |
| 474 SkColor textColor = m_textCompositeColor.rgb(); | |
| 475 for (int y = 0; y < m_layerSize.height(); y++) { | |
| 476 uint32_t* row = bitmap.getAddr32(0, y); | |
| 477 for (int x = 0; x < m_layerSize.width(); x++) { | |
| 478 // The alpha is the average of the R, G, and B channels. | |
| 479 int alpha = (SkGetPackedR32(row[x]) + SkGetPackedG32(row[x]) + SkGet
PackedB32(row[x])) / 3; | |
| 480 | |
| 481 // Apply that alpha to the text color and write the result. | |
| 482 row[x] = SkAlphaMulQ(textColor, SkAlpha255To256(255 - alpha)); | |
| 483 } | |
| 484 } | |
| 485 | |
| 486 // Now the layer has text with the proper color and opacity. | |
| 487 m_destContext->save(); | |
| 488 | |
| 489 // We want to use Untransformed space (see above) | |
| 490 SkMatrix identity; | |
| 491 identity.reset(); | |
| 492 m_destContext->setMatrix(identity); | |
| 493 SkRect destRect = { m_transformedSourceRect.x(), m_transformedSourceRect.y()
, m_transformedSourceRect.maxX(), m_transformedSourceRect.maxY() }; | |
| 494 | |
| 495 // Note that we need to specify the source layer subset, since the bitmap | |
| 496 // may have been cached and it could be larger than what we're using. | |
| 497 SkRect sourceRect = SkRect::MakeWH( | |
| 498 SkIntToScalar(m_layerSize.width()), | |
| 499 SkIntToScalar(m_layerSize.height())); | |
| 500 m_destContext->drawBitmapRect(bitmap, &sourceRect, destRect, 0); | |
| 501 m_destContext->restore(); | |
| 502 } | |
| 503 | |
| 504 void TransparencyWin::makeLayerOpaque() | |
| 505 { | |
| 506 if (!m_validLayer) | |
| 507 return; | |
| 508 | |
| 509 SkBitmap& bitmap = const_cast<SkBitmap&>(m_drawContext->layerBitmap(Graphics
Context::ReadWrite)); | |
| 510 for (int y = 0; y < m_layerSize.height(); y++) { | |
| 511 uint32_t* row = bitmap.getAddr32(0, y); | |
| 512 for (int x = 0; x < m_layerSize.width(); x++) | |
| 513 row[x] |= 0xFF000000; | |
| 514 } | |
| 515 } | |
| 516 | |
| 517 } // namespace WebCore | |
| OLD | NEW |