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