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

Side by Side Diff: Source/core/platform/graphics/chromium/TransparencyWin.cpp

Issue 26679003: Move platform/graphics/chromium/* to platform/graphics/ (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: rename fix Created 7 years, 1 month 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
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 <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
OLDNEW
« no previous file with comments | « Source/core/platform/graphics/chromium/TransparencyWin.h ('k') | Source/core/platform/graphics/chromium/UniscribeHelper.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698