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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:mergeinfo
OLDNEW
(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 "config.h"
32 #include <windows.h>
33
34 #include "GraphicsContext.h"
35 #include "ImageBuffer.h"
36 #include "PlatformContextSkia.h"
37 #include "SimpleFontData.h"
38 #include "TransformationMatrix.h"
39 #include "TransparencyWin.h"
40
41 #include "SkColorPriv.h"
42 #include "skia/ext/platform_canvas.h"
43
44 namespace WebCore {
45
46 namespace {
47
48 // If either of these pointers is non-NULL, both must be valid and point to
49 // bitmaps of the same size.
50 struct StaticBuffer
51 {
52 // The destination bitmap we're drawing into.
53 ImageBuffer* destBitmap;
54
55 // This could be an ImageBuffer but this is an optimization. Since this is
56 // only ever used as a reference, we don't need to make a full
57 // PlatformCanvas using Skia on Windows. Just allocating a regular SkBitmap
58 // is much faster since it's just a Malloc rather than a GDI call.
59 SkBitmap* referenceBitmap;
60 } staticBuffer = {NULL, NULL};
61
62 // The maximum size in pixels of the buffer we'll keep around for drawing text
63 // into. Buffers larger than this will be destroyed when we're done with them.
64 const int maxCachedBufferPixelSize = 65536;
65
66 inline skia::PlatformCanvas* canvasForContext(GraphicsContext* context)
67 {
68 return context->platformContext()->canvas();
69 }
70
71 inline const SkBitmap& bitmapForContext(GraphicsContext* context)
72 {
73 return canvasForContext(context)->
74 getTopPlatformDevice().accessBitmap(false);
75 }
76
77 void compositeToCopy(GraphicsContext* sourceLayers,
78 GraphicsContext* destContext,
79 const TransformationMatrix& matrix)
80 {
81 // Make a list of all devices. The iterator goes top-down, and we want
82 // bottom-up.
83 struct DeviceInfo {
84 DeviceInfo(SkDevice* d, int lx, int ly)
85 : device(d)
86 , x(lx)
87 , y(ly) {}
88 SkDevice* device;
89 int x, y;
90 };
91 Vector<DeviceInfo> devices;
92 SkCanvas* sourceCanvas = canvasForContext(sourceLayers);
93 SkCanvas::LayerIter iter(sourceCanvas, false);
94 while (!iter.done()) {
95 devices.append(DeviceInfo(iter.device(), iter.x(), iter.y()));
96 iter.next();
97 }
98
99 // Create a temporary canvas for the compositing into the destination.
100 SkBitmap* destBmp = const_cast<SkBitmap*>(&bitmapForContext(destContext));
101 SkCanvas destCanvas(*destBmp);
102 destCanvas.setMatrix(matrix);
103
104 for (int i = devices.size() - 1; i >= 0; i--) {
105 const SkBitmap& srcBmp = devices[i].device->accessBitmap(false);
106
107 SkRect destRect;
108 destRect.fLeft = devices[i].x;
109 destRect.fTop = devices[i].y;
110 destRect.fRight = destRect.fLeft + srcBmp.width();
111 destRect.fBottom = destRect.fTop + srcBmp.height();
112
113 destCanvas.drawBitmapRect(srcBmp, NULL, destRect);
114 }
115 }
116
117 } // namespace
118
119 TransparencyWin::TransparencyWin()
120 : m_destContext(0)
121 , m_orgTransform()
122 , m_layerMode(NoLayer)
123 , m_transformMode(KeepTransform)
124 , m_drawContext(0)
125 , m_savedOnDrawContext(false)
126 , m_layerBuffer(0)
127 , m_referenceBitmap(0)
128 {
129 }
130
131 TransparencyWin::~TransparencyWin()
132 {
133 // Matches the save() in initializeNewTextContext (or the constructor for
134 // SCALE) to put the context back into the same state we found it.
135 if (m_savedOnDrawContext)
136 m_drawContext->restore();
137
138 switch (m_layerMode) {
139 case NoLayer:
140 break;
141 case OpaqueCompositeLayer:
142 case WhiteLayer:
143 compositeOpaqueComposite();
144 break;
145 case TextComposite:
146 compositeTextComposite();
147 break;
148 }
149 }
150
151 void TransparencyWin::init(GraphicsContext* dest,
152 LayerMode layerMode,
153 TransformMode transformMode,
154 const IntRect& region) {
155 m_destContext = dest;
156 m_orgTransform = dest->getCTM();
157 m_layerMode = layerMode;
158 m_transformMode = transformMode;
159 m_sourceRect = region;
160
161 setupLayer(region);
162 setupTransform(region);
163 }
164
165 void TransparencyWin::setupLayer(const IntRect& region)
166 {
167 // Compute the size of the layer we're making.
168 if (m_transformMode == Untransform) {
169 // The meaning of the "transformed" source rect is a little ambigous
170 // here. The rest of the code doesn't care about it in the Untransform
171 // case since we're using our own happy coordinate system. So we set it
172 // to be the source rect since that matches how the code below actually
173 // uses the variable: to determine how to translate things to account
174 // for the offset of the layer.
175 m_transformedSourceRect = m_sourceRect;
176 m_layerSize = IntSize(m_sourceRect.width(), m_sourceRect.height());
177 } else {
178 m_transformedSourceRect = m_orgTransform.mapRect(m_sourceRect);
179 m_layerSize = IntSize(m_transformedSourceRect.width(), m_transformedSour ceRect.height());
180 }
181
182 switch (m_layerMode) {
183 case NoLayer:
184 m_drawContext = m_destContext; // Draw to the source context.
185 break;
186 case OpaqueCompositeLayer: {
187 initializeNewContext();
188
189 TransformationMatrix mapping;
190 mapping.translate(-m_transformedSourceRect.x(), -m_transformedSourceRect .y());
191 if (m_transformMode == Untransform){
192 // Compute the inverse mapping from the canvas space to the
193 // coordinate space of our bitmap.
194 mapping = m_orgTransform.inverse() * mapping;
195 }
196 compositeToCopy(m_destContext, m_drawContext, mapping);
197
198 // Save the reference layer so we can tell what changed.
199 SkCanvas referenceCanvas(*m_referenceBitmap);
200 referenceCanvas.drawBitmap(bitmapForContext(m_drawContext), 0, 0);
201 // Layer rect represents the part of the original layer.
202 break;
203 }
204 case TextComposite:
205 ASSERT(m_transformMode == KeepTransform);
206 // Fall through to filling with white.
207 case WhiteLayer:
208 initializeNewContext();
209 m_drawContext->fillRect(IntRect(IntPoint(0, 0), m_layerSize), Color::whi te);
210 // Layer rect represents the part of the original layer.
211 break;
212 }
213 }
214
215 void TransparencyWin::setupTransform(const IntRect& region)
216 {
217 switch (m_transformMode) {
218 case KeepTransform:
219 if (m_layerMode != NoLayer) {
220 // Need to save things since we're modifying the transform.
221 m_drawContext->save();
222 m_savedOnDrawContext = true;
223
224 // Account for the fact that the layer may be offset from the
225 // original. This only happens when we create a layer that has the
226 // same coordinate space as the parent.
227 TransformationMatrix xform;
228 xform.translate(-m_transformedSourceRect.x(), -m_transformedSourceRe ct.y());
229
230 // We're making a layer, so apply the old transform to the new one
231 // so it's maintained. We know the new layer has the identity
232 // transform now, we we can just multiply it.
233 xform = m_orgTransform * xform;
234 m_drawContext->concatCTM(xform);
235 }
236 m_drawRect = m_sourceRect;
237 break;
238 case Untransform:
239 ASSERT(m_layerMode != NoLayer);
240 // We now have a new layer with the identity transform, which is the
241 // Untransformed space we'll use for drawing.
242 m_drawRect = IntRect(IntPoint(0, 0), m_layerSize);
243 break;
244 case ScaleTransform:
245 if (m_layerMode == NoLayer) {
246 // Need to save things since we're modifying the layer.
247 m_drawContext->save();
248 m_savedOnDrawContext = true;
249
250 // Undo the transform on the current layer when we're re-using the
251 // current one.
252 m_drawContext->concatCTM(m_drawContext->getCTM().inverse());
253
254 // We're drawing to the original layer with just a different size.
255 m_drawRect = m_transformedSourceRect;
256 } else {
257 // Just go ahead and use the layer's coordinate space to draw into.
258 // It will have the scaled size, and an identity transform loaded.
259 m_drawRect = IntRect(IntPoint(0, 0), m_layerSize);
260 }
261 break;
262 }
263 }
264
265 void TransparencyWin::setTextCompositeColor(Color color)
266 {
267 m_textCompositeColor = color;
268 }
269
270 void TransparencyWin::initializeNewContext()
271 {
272 int pixelSize = m_layerSize.width() * m_layerSize.height();
273 if (pixelSize > maxCachedBufferPixelSize) {
274 // Create a 1-off buffer for drawing into.
275 m_ownedBuffer.adopt(ImageBuffer::create(m_layerSize, false));
276 m_layerBuffer = m_ownedBuffer.get();
277
278 if (m_layerMode == OpaqueCompositeLayer) {
279 // Only create the reference buffer if needed. Below, we always
280 // create the buffer to reduce complexity when using the cached
281 // bitmap by keeping everything in sync.
282 m_ownedReferenceBuffer.set(new SkBitmap);
283 m_ownedReferenceBuffer->setConfig(SkBitmap::kARGB_8888_Config,
284 m_layerSize.width(),
285 m_layerSize.height());
286 m_ownedReferenceBuffer->allocPixels();
287 m_referenceBitmap = m_ownedReferenceBuffer.get();
288 }
289
290 m_drawContext = m_ownedBuffer->context();
291 return;
292 }
293
294 if (staticBuffer.destBitmap &&
295 staticBuffer.destBitmap->size().width() >= m_layerSize.width() &&
296 staticBuffer.destBitmap->size().height() >= m_layerSize.height()) {
297 // We can re-use the existing buffer. We don't need to clear it since
298 // all layer modes will clear it in their initialization.
299 m_drawContext = staticBuffer.destBitmap->context();
300 m_layerBuffer = staticBuffer.destBitmap;
301
302 m_referenceBitmap = staticBuffer.referenceBitmap;
303 return;
304 }
305
306 // Create a new cached buffer.
307 delete staticBuffer.destBitmap;
308 delete staticBuffer.referenceBitmap;
309
310 staticBuffer.destBitmap = ImageBuffer::create(m_layerSize, false).release();
311 staticBuffer.referenceBitmap = new SkBitmap;
312 staticBuffer.referenceBitmap->setConfig(SkBitmap::kARGB_8888_Config, m_layer Size.width(), m_layerSize.height());
313 staticBuffer.referenceBitmap->allocPixels();
314
315 m_layerBuffer = staticBuffer.destBitmap;
316 m_referenceBitmap = staticBuffer.referenceBitmap;
317 m_drawContext = staticBuffer.destBitmap->context();
318 }
319
320 void TransparencyWin::compositeOpaqueComposite()
321 {
322 SkCanvas* destCanvas = canvasForContext(m_destContext);
323 destCanvas->save();
324
325 SkBitmap* bitmap = const_cast<SkBitmap*>(
326 &bitmapForContext(m_layerBuffer->context()));
327
328 // This function will be called for WhiteLayer as well, which we don't want
329 // to change.
330 if (m_layerMode == OpaqueCompositeLayer) {
331 // Fix up our bitmap, making it contain only the pixels which changed
332 // and transparent everywhere else.
333 SkAutoLockPixels sourceLock(*m_referenceBitmap);
334 SkAutoLockPixels lock(*bitmap);
335 for (int y = 0; y < bitmap->height(); y++) {
336 uint32_t* source = m_referenceBitmap->getAddr32(0, y);
337 uint32_t* dest = bitmap->getAddr32(0, y);
338 for (int x = 0; x < bitmap->width(); x++) {
339 // Clear out any pixels that were untouched.
340 if (dest[x] == source[x])
341 dest[x] = 0;
342 else
343 dest[x] |= (0xFF << SK_A32_SHIFT);
344 }
345 }
346 } else
347 makeLayerOpaque();
348
349 SkRect destRect;
350 if (m_transformMode != Untransform) {
351 // We want to use Untransformed space.
352 //
353 // Note that we DON'T call m_layerBuffer->image() here. This actually
354 // makes a copy of the image, which is unnecessary and slow. Instead, we
355 // just draw the image from inside the destination context.
356 SkMatrix identity;
357 identity.reset();
358 destCanvas->setMatrix(identity);
359
360 destRect.set(m_transformedSourceRect.x(), m_transformedSourceRect.y(), m _transformedSourceRect.right(), m_transformedSourceRect.bottom());
361 } else {
362 destRect.set(m_sourceRect.x(), m_sourceRect.y(), m_sourceRect.right(), m _sourceRect.bottom());
363 }
364
365 SkPaint paint;
366 paint.setFilterBitmap(true);
367 paint.setAntiAlias(true);
368
369 // Note that we need to specify the source layer subset, since the bitmap
370 // may have been cached and it could be larger than what we're using.
371 SkIRect sourceRect = { 0, 0, m_layerSize.width(), m_layerSize.height() };
372 destCanvas->drawBitmapRect(*bitmap, &sourceRect, destRect, &paint);
373 destCanvas->restore();
374 }
375
376 void TransparencyWin::compositeTextComposite()
377 {
378 const SkBitmap& bitmap = m_layerBuffer->context()->platformContext()->
379 canvas()->getTopPlatformDevice().accessBitmap(true);
380 SkColor textColor = m_textCompositeColor.rgb();
381 for (int y = 0; y < m_layerSize.height(); y++) {
382 uint32_t* row = bitmap.getAddr32(0, y);
383 for (int x = 0; x < m_layerSize.width(); x++) {
384 // The alpha is the average of the R, G, and B channels.
385 int alpha = (SkGetPackedR32(row[x]) + SkGetPackedG32(row[x]) +
386 SkGetPackedB32(row[x])) / 3;
387
388 // Apply that alpha to the text color and write the result.
389 row[x] = SkAlphaMulQ(textColor, SkAlpha255To256(255 - alpha));
390 }
391 }
392
393 // Now the layer has text with the proper color and opacity.
394 SkCanvas* destCanvas = canvasForContext(m_destContext);
395
396 // We want to use Untransformed space (see above)
397 SkMatrix identity;
398 identity.reset();
399 destCanvas->setMatrix(identity);
400 SkRect destRect = { m_transformedSourceRect.x(), m_transformedSourceRect.y() , m_transformedSourceRect.right(), m_transformedSourceRect.bottom() };
401
402 // Note that we need to specify the source layer subset, since the bitmap
403 // may have been cached and it could be larger than what we're using.
404 SkIRect sourceRect = { 0, 0, m_layerSize.width(), m_layerSize.height() };
405 destCanvas->drawBitmapRect(bitmap, &sourceRect, destRect, NULL);
406 destCanvas->restore();
407 }
408
409 void TransparencyWin::makeLayerOpaque()
410 {
411 SkBitmap& bitmap = const_cast<SkBitmap&>(m_drawContext->platformContext()->
412 canvas()->getTopPlatformDevice().accessBitmap(true));
413 for (int y = 0; y < m_layerSize.height(); y++) {
414 uint32_t* row = bitmap.getAddr32(0, y);
415 for (int x = 0; x < m_layerSize.width(); x++)
416 row[x] |= 0xFF000000;
417 }
418 }
419
420 } // namespace WebCore
421
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698