TransparencyWin.cpp [plain text]
#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 {
const int maxCachedBufferPixelSize = 65536;
inline skia::PlatformCanvas* canvasForContext(const GraphicsContext& context)
{
return context.platformContext()->canvas();
}
inline const SkBitmap& bitmapForContext(const GraphicsContext& context)
{
return canvasForContext(context)->getTopPlatformDevice().accessBitmap(false);
}
void compositeToCopy(const GraphicsContext& sourceLayers,
GraphicsContext& destContext,
const TransformationMatrix& matrix)
{
struct DeviceInfo {
DeviceInfo(SkDevice* d, int lx, int ly)
: device(d)
, x(lx)
, y(ly) {}
SkDevice* device;
int x;
int 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();
}
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, 0, destRect);
}
}
}
class TransparencyWin::OwnedBuffers {
public:
OwnedBuffers(const IntSize& size, bool needReferenceBuffer)
{
m_destBitmap = ImageBuffer::create(size, false);
if (needReferenceBuffer) {
m_referenceBitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height());
m_referenceBitmap.allocPixels();
m_referenceBitmap.eraseARGB(0, 0, 0, 0);
}
}
ImageBuffer* destBitmap() { return m_destBitmap.get(); }
SkBitmap* referenceBitmap() { return &m_referenceBitmap; }
bool canHandleSize(const IntSize& size) const
{
return m_destBitmap->size().width() >= size.width() && m_destBitmap->size().height() >= size.height();
}
private:
OwnPtr<ImageBuffer> m_destBitmap;
SkBitmap m_referenceBitmap;
};
TransparencyWin::OwnedBuffers* TransparencyWin::m_cachedBuffers = 0;
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)
, m_validLayer(false)
{
}
TransparencyWin::~TransparencyWin()
{
ASSERT(!m_savedOnDrawContext);
}
void TransparencyWin::composite()
{
if (m_savedOnDrawContext) {
m_drawContext->restore();
m_savedOnDrawContext = false;
}
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;
computeLayerSize();
setupLayer();
setupTransform(region);
}
void TransparencyWin::computeLayerSize()
{
if (m_transformMode == Untransform) {
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());
}
}
void TransparencyWin::setupLayer()
{
switch (m_layerMode) {
case NoLayer:
setupLayerForNoLayer();
break;
case OpaqueCompositeLayer:
setupLayerForOpaqueCompositeLayer();
break;
case TextComposite:
setupLayerForTextComposite();
break;
case WhiteLayer:
setupLayerForWhiteLayer();
break;
}
}
void TransparencyWin::setupLayerForNoLayer()
{
m_drawContext = m_destContext; m_validLayer = true;
}
void TransparencyWin::setupLayerForOpaqueCompositeLayer()
{
initializeNewContext();
if (!m_validLayer)
return;
TransformationMatrix mapping;
mapping.translate(-m_transformedSourceRect.x(), -m_transformedSourceRect.y());
if (m_transformMode == Untransform){
mapping = m_orgTransform.inverse() * mapping;
}
compositeToCopy(*m_destContext, *m_drawContext, mapping);
SkCanvas referenceCanvas(*m_referenceBitmap);
referenceCanvas.drawBitmap(bitmapForContext(*m_drawContext), 0, 0);
}
void TransparencyWin::setupLayerForTextComposite()
{
ASSERT(m_transformMode == KeepTransform);
setupLayerForWhiteLayer();
}
void TransparencyWin::setupLayerForWhiteLayer()
{
initializeNewContext();
if (!m_validLayer)
return;
m_drawContext->fillRect(IntRect(IntPoint(0, 0), m_layerSize), Color::white);
}
void TransparencyWin::setupTransform(const IntRect& region)
{
switch (m_transformMode) {
case KeepTransform:
setupTransformForKeepTransform(region);
break;
case Untransform:
setupTransformForUntransform();
break;
case ScaleTransform:
setupTransformForScaleTransform();
break;
}
}
void TransparencyWin::setupTransformForKeepTransform(const IntRect& region)
{
if (!m_validLayer)
return;
if (m_layerMode != NoLayer) {
m_drawContext->save();
m_savedOnDrawContext = true;
TransformationMatrix xform;
xform.translate(-m_transformedSourceRect.x(), -m_transformedSourceRect.y());
xform = m_orgTransform * xform;
m_drawContext->concatCTM(xform);
}
m_drawRect = m_sourceRect;
}
void TransparencyWin::setupTransformForUntransform()
{
ASSERT(m_layerMode != NoLayer);
m_drawRect = IntRect(IntPoint(0, 0), m_layerSize);
}
void TransparencyWin::setupTransformForScaleTransform()
{
if (!m_validLayer)
return;
if (m_layerMode == NoLayer) {
m_drawContext->save();
m_savedOnDrawContext = true;
m_drawContext->concatCTM(m_drawContext->getCTM().inverse());
m_drawRect = m_transformedSourceRect;
} else {
m_drawRect = IntRect(IntPoint(0, 0), m_layerSize);
}
}
void TransparencyWin::setTextCompositeColor(Color color)
{
m_textCompositeColor = color;
}
void TransparencyWin::initializeNewContext()
{
int pixelSize = m_layerSize.width() * m_layerSize.height();
if (pixelSize <= 0)
return;
if (pixelSize > maxCachedBufferPixelSize) {
bool needReferenceBitmap = m_layerMode == OpaqueCompositeLayer;
m_ownedBuffers.set(new OwnedBuffers(m_layerSize, needReferenceBitmap));
m_layerBuffer = m_ownedBuffers->destBitmap();
if (!m_layerBuffer)
return;
m_drawContext = m_layerBuffer->context();
if (needReferenceBitmap)
m_referenceBitmap = m_ownedBuffers->referenceBitmap();
m_validLayer = true;
return;
}
if (m_cachedBuffers && m_cachedBuffers->canHandleSize(m_layerSize)) {
m_layerBuffer = m_cachedBuffers->destBitmap();
m_drawContext = m_cachedBuffers->destBitmap()->context();
bitmapForContext(*m_drawContext).eraseARGB(0, 0, 0, 0);
m_referenceBitmap = m_cachedBuffers->referenceBitmap();
m_referenceBitmap->eraseARGB(0, 0, 0, 0);
m_validLayer = true;
return;
}
if (m_cachedBuffers)
delete m_cachedBuffers;
m_cachedBuffers = new OwnedBuffers(m_layerSize, true);
m_layerBuffer = m_cachedBuffers->destBitmap();
m_drawContext = m_cachedBuffers->destBitmap()->context();
m_referenceBitmap = m_cachedBuffers->referenceBitmap();
m_validLayer = true;
}
void TransparencyWin::compositeOpaqueComposite()
{
if (!m_validLayer)
return;
SkCanvas* destCanvas = canvasForContext(*m_destContext);
destCanvas->save();
SkBitmap* bitmap = const_cast<SkBitmap*>(
&bitmapForContext(*m_layerBuffer->context()));
if (m_layerMode == OpaqueCompositeLayer) {
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++) {
if (dest[x] == source[x])
dest[x] = 0;
else
dest[x] |= (0xFF << SK_A32_SHIFT);
}
}
} else
makeLayerOpaque();
SkRect destRect;
if (m_transformMode != Untransform) {
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);
SkIRect sourceRect = { 0, 0, m_layerSize.width(), m_layerSize.height() };
destCanvas->drawBitmapRect(*bitmap, &sourceRect, destRect, &paint);
destCanvas->restore();
}
void TransparencyWin::compositeTextComposite()
{
if (!m_validLayer)
return;
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++) {
int alpha = (SkGetPackedR32(row[x]) + SkGetPackedG32(row[x]) + SkGetPackedB32(row[x])) / 3;
row[x] = SkAlphaMulQ(textColor, SkAlpha255To256(255 - alpha));
}
}
SkCanvas* destCanvas = canvasForContext(*m_destContext);
SkMatrix identity;
identity.reset();
destCanvas->setMatrix(identity);
SkRect destRect = { m_transformedSourceRect.x(), m_transformedSourceRect.y(), m_transformedSourceRect.right(), m_transformedSourceRect.bottom() };
SkIRect sourceRect = { 0, 0, m_layerSize.width(), m_layerSize.height() };
destCanvas->drawBitmapRect(bitmap, &sourceRect, destRect, 0);
destCanvas->restore();
}
void TransparencyWin::makeLayerOpaque()
{
if (!m_validLayer)
return;
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;
}
}
}