Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(836)

Unified Diff: third_party/WebKit/WebCore/platform/graphics/chromium/TransparencyWin.cpp

Issue 21201: Transparency (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/WebCore/platform/graphics/chromium/TransparencyWin.cpp
===================================================================
--- third_party/WebKit/WebCore/platform/graphics/chromium/TransparencyWin.cpp (revision 0)
+++ third_party/WebKit/WebCore/platform/graphics/chromium/TransparencyWin.cpp (revision 0)
@@ -0,0 +1,421 @@
+/*
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include <windows.h>
+
+#include "GraphicsContext.h"
+#include "ImageBuffer.h"
+#include "PlatformContextSkia.h"
+#include "SimpleFontData.h"
+#include "TransformationMatrix.h"
+#include "TransparencyWin.h"
+
+#include "SkColorPriv.h"
+#include "skia/ext/platform_canvas.h"
+
+namespace WebCore {
+
+namespace {
+
+// If either of these pointers is non-NULL, both must be valid and point to
+// bitmaps of the same size.
+struct StaticBuffer
+{
+ // The destination bitmap we're drawing into.
+ ImageBuffer* destBitmap;
+
+ // This could be an ImageBuffer but this is an optimization. Since this is
+ // only ever used as a reference, we don't need to make a full
+ // PlatformCanvas using Skia on Windows. Just allocating a regular SkBitmap
+ // is much faster since it's just a Malloc rather than a GDI call.
+ SkBitmap* referenceBitmap;
+} staticBuffer = {NULL, NULL};
+
+// The maximum size in pixels of the buffer we'll keep around for drawing text
+// into. Buffers larger than this will be destroyed when we're done with them.
+const int maxCachedBufferPixelSize = 65536;
+
+inline skia::PlatformCanvas* canvasForContext(GraphicsContext* context)
+{
+ return context->platformContext()->canvas();
+}
+
+inline const SkBitmap& bitmapForContext(GraphicsContext* context)
+{
+ return canvasForContext(context)->
+ getTopPlatformDevice().accessBitmap(false);
+}
+
+void compositeToCopy(GraphicsContext* sourceLayers,
+ GraphicsContext* destContext,
+ const TransformationMatrix& matrix)
+{
+ // Make a list of all devices. The iterator goes top-down, and we want
+ // bottom-up.
+ struct DeviceInfo {
+ DeviceInfo(SkDevice* d, int lx, int ly)
+ : device(d)
+ , x(lx)
+ , y(ly) {}
+ SkDevice* device;
+ int x, y;
+ };
+ Vector<DeviceInfo> devices;
+ SkCanvas* sourceCanvas = canvasForContext(sourceLayers);
+ SkCanvas::LayerIter iter(sourceCanvas, false);
+ while (!iter.done()) {
+ devices.append(DeviceInfo(iter.device(), iter.x(), iter.y()));
+ iter.next();
+ }
+
+ // Create a temporary canvas for the compositing into the destination.
+ SkBitmap* destBmp = const_cast<SkBitmap*>(&bitmapForContext(destContext));
+ SkCanvas destCanvas(*destBmp);
+ destCanvas.setMatrix(matrix);
+
+ for (int i = devices.size() - 1; i >= 0; i--) {
+ const SkBitmap& srcBmp = devices[i].device->accessBitmap(false);
+
+ SkRect destRect;
+ destRect.fLeft = devices[i].x;
+ destRect.fTop = devices[i].y;
+ destRect.fRight = destRect.fLeft + srcBmp.width();
+ destRect.fBottom = destRect.fTop + srcBmp.height();
+
+ destCanvas.drawBitmapRect(srcBmp, NULL, destRect);
+ }
+}
+
+} // namespace
+
+TransparencyWin::TransparencyWin()
+ : m_destContext(0)
+ , m_orgTransform()
+ , m_layerMode(NoLayer)
+ , m_transformMode(KeepTransform)
+ , m_drawContext(0)
+ , m_savedOnDrawContext(false)
+ , m_layerBuffer(0)
+ , m_referenceBitmap(0)
+{
+}
+
+TransparencyWin::~TransparencyWin()
+{
+ // Matches the save() in initializeNewTextContext (or the constructor for
+ // SCALE) to put the context back into the same state we found it.
+ if (m_savedOnDrawContext)
+ m_drawContext->restore();
+
+ switch (m_layerMode) {
+ case NoLayer:
+ break;
+ case OpaqueCompositeLayer:
+ case WhiteLayer:
+ compositeOpaqueComposite();
+ break;
+ case TextComposite:
+ compositeTextComposite();
+ break;
+ }
+}
+
+void TransparencyWin::init(GraphicsContext* dest,
+ LayerMode layerMode,
+ TransformMode transformMode,
+ const IntRect& region) {
+ m_destContext = dest;
+ m_orgTransform = dest->getCTM();
+ m_layerMode = layerMode;
+ m_transformMode = transformMode;
+ m_sourceRect = region;
+
+ setupLayer(region);
+ setupTransform(region);
+}
+
+void TransparencyWin::setupLayer(const IntRect& region)
+{
+ // Compute the size of the layer we're making.
+ if (m_transformMode == Untransform) {
+ // The meaning of the "transformed" source rect is a little ambigous
+ // here. The rest of the code doesn't care about it in the Untransform
+ // case since we're using our own happy coordinate system. So we set it
+ // to be the source rect since that matches how the code below actually
+ // uses the variable: to determine how to translate things to account
+ // for the offset of the layer.
+ m_transformedSourceRect = m_sourceRect;
+ m_layerSize = IntSize(m_sourceRect.width(), m_sourceRect.height());
+ } else {
+ m_transformedSourceRect = m_orgTransform.mapRect(m_sourceRect);
+ m_layerSize = IntSize(m_transformedSourceRect.width(), m_transformedSourceRect.height());
+ }
+
+ switch (m_layerMode) {
+ case NoLayer:
+ m_drawContext = m_destContext; // Draw to the source context.
+ break;
+ case OpaqueCompositeLayer: {
+ initializeNewContext();
+
+ TransformationMatrix mapping;
+ mapping.translate(-m_transformedSourceRect.x(), -m_transformedSourceRect.y());
+ if (m_transformMode == Untransform){
+ // Compute the inverse mapping from the canvas space to the
+ // coordinate space of our bitmap.
+ mapping = m_orgTransform.inverse() * mapping;
+ }
+ compositeToCopy(m_destContext, m_drawContext, mapping);
+
+ // Save the reference layer so we can tell what changed.
+ SkCanvas referenceCanvas(*m_referenceBitmap);
+ referenceCanvas.drawBitmap(bitmapForContext(m_drawContext), 0, 0);
+ // Layer rect represents the part of the original layer.
+ break;
+ }
+ case TextComposite:
+ ASSERT(m_transformMode == KeepTransform);
+ // Fall through to filling with white.
+ case WhiteLayer:
+ initializeNewContext();
+ m_drawContext->fillRect(IntRect(IntPoint(0, 0), m_layerSize), Color::white);
+ // Layer rect represents the part of the original layer.
+ break;
+ }
+}
+
+void TransparencyWin::setupTransform(const IntRect& region)
+{
+ switch (m_transformMode) {
+ case KeepTransform:
+ if (m_layerMode != NoLayer) {
+ // Need to save things since we're modifying the transform.
+ m_drawContext->save();
+ m_savedOnDrawContext = true;
+
+ // Account for the fact that the layer may be offset from the
+ // original. This only happens when we create a layer that has the
+ // same coordinate space as the parent.
+ TransformationMatrix xform;
+ xform.translate(-m_transformedSourceRect.x(), -m_transformedSourceRect.y());
+
+ // We're making a layer, so apply the old transform to the new one
+ // so it's maintained. We know the new layer has the identity
+ // transform now, we we can just multiply it.
+ xform = m_orgTransform * xform;
+ m_drawContext->concatCTM(xform);
+ }
+ m_drawRect = m_sourceRect;
+ break;
+ case Untransform:
+ ASSERT(m_layerMode != NoLayer);
+ // We now have a new layer with the identity transform, which is the
+ // Untransformed space we'll use for drawing.
+ m_drawRect = IntRect(IntPoint(0, 0), m_layerSize);
+ break;
+ case ScaleTransform:
+ if (m_layerMode == NoLayer) {
+ // Need to save things since we're modifying the layer.
+ m_drawContext->save();
+ m_savedOnDrawContext = true;
+
+ // Undo the transform on the current layer when we're re-using the
+ // current one.
+ m_drawContext->concatCTM(m_drawContext->getCTM().inverse());
+
+ // We're drawing to the original layer with just a different size.
+ m_drawRect = m_transformedSourceRect;
+ } else {
+ // Just go ahead and use the layer's coordinate space to draw into.
+ // It will have the scaled size, and an identity transform loaded.
+ m_drawRect = IntRect(IntPoint(0, 0), m_layerSize);
+ }
+ break;
+ }
+}
+
+void TransparencyWin::setTextCompositeColor(Color color)
+{
+ m_textCompositeColor = color;
+}
+
+void TransparencyWin::initializeNewContext()
+{
+ int pixelSize = m_layerSize.width() * m_layerSize.height();
+ if (pixelSize > maxCachedBufferPixelSize) {
+ // Create a 1-off buffer for drawing into.
+ m_ownedBuffer.adopt(ImageBuffer::create(m_layerSize, false));
+ m_layerBuffer = m_ownedBuffer.get();
+
+ if (m_layerMode == OpaqueCompositeLayer) {
+ // Only create the reference buffer if needed. Below, we always
+ // create the buffer to reduce complexity when using the cached
+ // bitmap by keeping everything in sync.
+ m_ownedReferenceBuffer.set(new SkBitmap);
+ m_ownedReferenceBuffer->setConfig(SkBitmap::kARGB_8888_Config,
+ m_layerSize.width(),
+ m_layerSize.height());
+ m_ownedReferenceBuffer->allocPixels();
+ m_referenceBitmap = m_ownedReferenceBuffer.get();
+ }
+
+ m_drawContext = m_ownedBuffer->context();
+ return;
+ }
+
+ if (staticBuffer.destBitmap &&
+ staticBuffer.destBitmap->size().width() >= m_layerSize.width() &&
+ staticBuffer.destBitmap->size().height() >= m_layerSize.height()) {
+ // We can re-use the existing buffer. We don't need to clear it since
+ // all layer modes will clear it in their initialization.
+ m_drawContext = staticBuffer.destBitmap->context();
+ m_layerBuffer = staticBuffer.destBitmap;
+
+ m_referenceBitmap = staticBuffer.referenceBitmap;
+ return;
+ }
+
+ // Create a new cached buffer.
+ delete staticBuffer.destBitmap;
+ delete staticBuffer.referenceBitmap;
+
+ staticBuffer.destBitmap = ImageBuffer::create(m_layerSize, false).release();
+ staticBuffer.referenceBitmap = new SkBitmap;
+ staticBuffer.referenceBitmap->setConfig(SkBitmap::kARGB_8888_Config, m_layerSize.width(), m_layerSize.height());
+ staticBuffer.referenceBitmap->allocPixels();
+
+ m_layerBuffer = staticBuffer.destBitmap;
+ m_referenceBitmap = staticBuffer.referenceBitmap;
+ m_drawContext = staticBuffer.destBitmap->context();
+}
+
+void TransparencyWin::compositeOpaqueComposite()
+{
+ SkCanvas* destCanvas = canvasForContext(m_destContext);
+ destCanvas->save();
+
+ SkBitmap* bitmap = const_cast<SkBitmap*>(
+ &bitmapForContext(m_layerBuffer->context()));
+
+ // This function will be called for WhiteLayer as well, which we don't want
+ // to change.
+ if (m_layerMode == OpaqueCompositeLayer) {
+ // Fix up our bitmap, making it contain only the pixels which changed
+ // and transparent everywhere else.
+ SkAutoLockPixels sourceLock(*m_referenceBitmap);
+ SkAutoLockPixels lock(*bitmap);
+ for (int y = 0; y < bitmap->height(); y++) {
+ uint32_t* source = m_referenceBitmap->getAddr32(0, y);
+ uint32_t* dest = bitmap->getAddr32(0, y);
+ for (int x = 0; x < bitmap->width(); x++) {
+ // Clear out any pixels that were untouched.
+ if (dest[x] == source[x])
+ dest[x] = 0;
+ else
+ dest[x] |= (0xFF << SK_A32_SHIFT);
+ }
+ }
+ } else
+ makeLayerOpaque();
+
+ SkRect destRect;
+ if (m_transformMode != Untransform) {
+ // We want to use Untransformed space.
+ //
+ // Note that we DON'T call m_layerBuffer->image() here. This actually
+ // makes a copy of the image, which is unnecessary and slow. Instead, we
+ // just draw the image from inside the destination context.
+ SkMatrix identity;
+ identity.reset();
+ destCanvas->setMatrix(identity);
+
+ destRect.set(m_transformedSourceRect.x(), m_transformedSourceRect.y(), m_transformedSourceRect.right(), m_transformedSourceRect.bottom());
+ } else {
+ destRect.set(m_sourceRect.x(), m_sourceRect.y(), m_sourceRect.right(), m_sourceRect.bottom());
+ }
+
+ SkPaint paint;
+ paint.setFilterBitmap(true);
+ paint.setAntiAlias(true);
+
+ // Note that we need to specify the source layer subset, since the bitmap
+ // may have been cached and it could be larger than what we're using.
+ SkIRect sourceRect = { 0, 0, m_layerSize.width(), m_layerSize.height() };
+ destCanvas->drawBitmapRect(*bitmap, &sourceRect, destRect, &paint);
+ destCanvas->restore();
+}
+
+void TransparencyWin::compositeTextComposite()
+{
+ const SkBitmap& bitmap = m_layerBuffer->context()->platformContext()->
+ canvas()->getTopPlatformDevice().accessBitmap(true);
+ SkColor textColor = m_textCompositeColor.rgb();
+ for (int y = 0; y < m_layerSize.height(); y++) {
+ uint32_t* row = bitmap.getAddr32(0, y);
+ for (int x = 0; x < m_layerSize.width(); x++) {
+ // The alpha is the average of the R, G, and B channels.
+ int alpha = (SkGetPackedR32(row[x]) + SkGetPackedG32(row[x]) +
+ SkGetPackedB32(row[x])) / 3;
+
+ // Apply that alpha to the text color and write the result.
+ row[x] = SkAlphaMulQ(textColor, SkAlpha255To256(255 - alpha));
+ }
+ }
+
+ // Now the layer has text with the proper color and opacity.
+ SkCanvas* destCanvas = canvasForContext(m_destContext);
+
+ // We want to use Untransformed space (see above)
+ SkMatrix identity;
+ identity.reset();
+ destCanvas->setMatrix(identity);
+ SkRect destRect = { m_transformedSourceRect.x(), m_transformedSourceRect.y(), m_transformedSourceRect.right(), m_transformedSourceRect.bottom() };
+
+ // Note that we need to specify the source layer subset, since the bitmap
+ // may have been cached and it could be larger than what we're using.
+ SkIRect sourceRect = { 0, 0, m_layerSize.width(), m_layerSize.height() };
+ destCanvas->drawBitmapRect(bitmap, &sourceRect, destRect, NULL);
+ destCanvas->restore();
+}
+
+void TransparencyWin::makeLayerOpaque()
+{
+ SkBitmap& bitmap = const_cast<SkBitmap&>(m_drawContext->platformContext()->
+ canvas()->getTopPlatformDevice().accessBitmap(true));
+ for (int y = 0; y < m_layerSize.height(); y++) {
+ uint32_t* row = bitmap.getAddr32(0, y);
+ for (int x = 0; x < m_layerSize.width(); x++)
+ row[x] |= 0xFF000000;
+ }
+}
+
+} // namespace WebCore
+
Property changes on: third_party\WebKit\WebCore\platform\graphics\chromium\TransparencyWin.cpp
___________________________________________________________________
Added: svn:mergeinfo

Powered by Google App Engine
This is Rietveld 408576698