[Win] Enable Encrypted Media Support
[WebKit-https.git] / Source / WebCore / platform / graphics / ca / win / PlatformCALayerWinInternal.cpp
1 /*
2  * Copyright (C) 2011 Apple 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
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27
28 #include "PlatformCALayerWinInternal.h"
29
30 #include "Font.h"
31 #include "FontCache.h"
32 #include "GraphicsContext.h"
33 #include "PlatformCALayer.h"
34 #include "TextRun.h"
35 #include "TileController.h"
36 #include "TiledBacking.h"
37 #include <QuartzCore/CACFLayer.h>
38 #include <wtf/MainThread.h>
39
40 using namespace std;
41 using namespace WebCore;
42
43 // The width and height of a single tile in a tiled layer. Should be large enough to
44 // avoid lots of small tiles (and therefore lots of drawing callbacks), but small enough
45 // to keep the overall tile cost low.
46 static const int cTiledLayerTileSize = 512;
47
48 static bool layerTypeIsTiled(const PlatformCALayer::LayerType layerType)
49 {
50     return layerType == PlatformCALayer::LayerTypeWebTiledLayer
51         || layerType == PlatformCALayer::LayerTypePageTiledBackingLayer
52         || layerType == PlatformCALayer::LayerTypeTiledBackingLayer;
53 }
54
55 PlatformCALayerWinInternal::PlatformCALayerWinInternal(PlatformCALayer* owner)
56     : m_tileSize(CGSizeMake(cTiledLayerTileSize, cTiledLayerTileSize))
57     , m_constrainedSize(constrainedSize(owner->bounds().size()))
58     , m_owner(owner)
59 {
60     if (layerTypeIsTiled(m_owner->layerType())) {
61         // Tiled layers are placed in a child layer that is always the first child of the TiledLayer
62         m_tileParent = adoptCF(CACFLayerCreate(kCACFLayer));
63         CACFLayerInsertSublayer(m_owner->platformLayer(), m_tileParent.get(), 0);
64         updateTiles();
65     }
66 }
67
68 PlatformCALayerWinInternal::~PlatformCALayerWinInternal()
69 {
70 }
71
72 struct DisplayOnMainThreadContext {
73     RetainPtr<CACFLayerRef> layer;
74     RetainPtr<CGContextRef> context;
75
76     DisplayOnMainThreadContext(CACFLayerRef caLayer, CGContextRef caContext)
77         : layer(caLayer)
78         , context(caContext)
79     {
80     }
81 };
82
83 static void redispatchOnMainQueue(void* context)
84 {
85     ASSERT(isMainThread());
86     std::unique_ptr<DisplayOnMainThreadContext> retainedContext(reinterpret_cast<DisplayOnMainThreadContext*>(context));
87     if (!retainedContext)
88         return;
89
90     PlatformCALayerWinInternal* self = static_cast<PlatformCALayerWinInternal*>(CACFLayerGetUserData(retainedContext->layer.get()));
91
92     self->displayCallback(retainedContext->layer.get(), retainedContext->context.get());
93 }
94
95 void PlatformCALayerWinInternal::displayCallback(CACFLayerRef caLayer, CGContextRef context)
96 {
97     if (!isMainThread()) {
98         dispatch_async_f(dispatch_get_main_queue(), new DisplayOnMainThreadContext(caLayer, context), redispatchOnMainQueue);
99         return;
100     }
101     
102     if (!owner() || !owner()->owner())
103         return;
104
105     CGContextSaveGState(context);
106
107     CGRect layerBounds = owner()->bounds();
108     if (owner()->owner()->platformCALayerContentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) {
109         CGContextScaleCTM(context, 1, -1);
110         CGContextTranslateCTM(context, 0, -layerBounds.size.height);
111     }
112
113     if (owner()->owner()) {
114         GraphicsContext graphicsContext(context);
115
116         // It's important to get the clip from the context, because it may be significantly
117         // smaller than the layer bounds (e.g. tiled layers)
118         CGRect clipBounds = CGContextGetClipBoundingBox(context);
119         IntRect clip(enclosingIntRect(clipBounds));
120         owner()->owner()->platformCALayerPaintContents(owner(), graphicsContext, clip);
121     }
122 #ifndef NDEBUG
123     else {
124         ASSERT_NOT_REACHED();
125
126         // FIXME: ideally we'd avoid calling -setNeedsDisplay on a layer that is a plain color,
127         // so CA never makes backing store for it (which is what -setNeedsDisplay will do above).
128         CGContextSetRGBFillColor(context, 0.0f, 1.0f, 0.0f, 1.0f);
129         CGContextFillRect(context, layerBounds);
130     }
131 #endif
132
133     if (owner()->owner()->platformCALayerShowRepaintCounter(owner())) {
134         FontCachePurgePreventer fontCachePurgePreventer;
135
136         String text = String::number(owner()->owner()->platformCALayerIncrementRepaintCount(owner()));
137
138         CGContextSaveGState(context);
139
140         // Make the background of the counter the same as the border color,
141         // unless there is no border, then make it red
142         float borderWidth = CACFLayerGetBorderWidth(caLayer);
143         if (borderWidth > 0) {
144             CGColorRef borderColor = CACFLayerGetBorderColor(caLayer);
145             const CGFloat* colors = CGColorGetComponents(borderColor);
146             CGContextSetRGBFillColor(context, colors[0], colors[1], colors[2], colors[3]);
147         } else
148             CGContextSetRGBFillColor(context, 1.0f, 0.0f, 0.0f, 0.8f);
149         
150         CGRect aBounds = layerBounds;
151
152         aBounds.size.width = 10 + 10 * text.length();
153         aBounds.size.height = 22;
154         CGContextFillRect(context, aBounds);
155         
156         FontDescription desc;
157
158         NONCLIENTMETRICS metrics;
159         metrics.cbSize = sizeof(metrics);
160         SystemParametersInfo(SPI_GETNONCLIENTMETRICS, metrics.cbSize, &metrics, 0);
161         desc.setOneFamily(metrics.lfSmCaptionFont.lfFaceName);
162
163         desc.setComputedSize(18);
164         
165         Font font = Font(desc, 0, 0);
166         font.update(0);
167
168         GraphicsContext cg(context);
169         cg.setFillColor(Color::black, ColorSpaceDeviceRGB);
170         cg.drawText(font, TextRun(text), IntPoint(aBounds.origin.x + 5, aBounds.origin.y + 17));
171
172         CGContextRestoreGState(context);        
173     }
174
175     CGContextRestoreGState(context);
176
177     owner()->owner()->platformCALayerLayerDidDisplay(owner());
178 }
179
180 void PlatformCALayerWinInternal::internalSetNeedsDisplay(const FloatRect* dirtyRect)
181 {
182     if (dirtyRect) {
183         CGRect rect = *dirtyRect;
184         CACFLayerSetNeedsDisplay(owner()->platformLayer(), &rect);
185     } else
186         CACFLayerSetNeedsDisplay(owner()->platformLayer(), 0);
187 }
188
189 void PlatformCALayerWinInternal::setNeedsDisplay()
190 {
191     internalSetNeedsDisplay(0);
192 }
193
194 void PlatformCALayerWinInternal::setNeedsDisplayInRect(const FloatRect& dirtyRect)
195 {
196     if (layerTypeIsTiled(m_owner->layerType())) {
197         // FIXME: Only setNeedsDisplay for tiles that are currently visible
198         int numTileLayers = tileCount();
199         CGRect rect = dirtyRect;
200         for (int i = 0; i < numTileLayers; ++i)
201             CACFLayerSetNeedsDisplay(tileAtIndex(i), &rect);
202
203         if (m_owner->owner() && m_owner->owner()->platformCALayerShowRepaintCounter(m_owner)) {
204             CGRect layerBounds = m_owner->bounds();
205             CGRect indicatorRect = CGRectMake(layerBounds.origin.x, layerBounds.origin.y, 80, 25);
206             CACFLayerSetNeedsDisplay(tileAtIndex(0), &indicatorRect);
207         }
208     } else if (owner()->layerType() == PlatformCALayer::LayerTypeWebLayer) {
209         if (owner() && owner()->owner()) {
210             if (owner()->owner()->platformCALayerShowRepaintCounter(owner())) {
211                 FloatRect layerBounds = owner()->bounds();
212                 FloatRect repaintCounterRect = layerBounds;
213
214                 // We assume a maximum of 4 digits and a font size of 18.
215                 repaintCounterRect.setWidth(80);
216                 repaintCounterRect.setHeight(22);
217                 if (owner()->owner()->platformCALayerContentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown)
218                     repaintCounterRect.setY(layerBounds.height() - (layerBounds.y() + repaintCounterRect.height()));
219                 internalSetNeedsDisplay(&repaintCounterRect);
220             }
221             if (owner()->owner()->platformCALayerContentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) {
222                 FloatRect flippedDirtyRect = dirtyRect;
223                 flippedDirtyRect.setY(owner()->bounds().height() - (flippedDirtyRect.y() + flippedDirtyRect.height()));
224                 internalSetNeedsDisplay(&flippedDirtyRect);
225                 return;
226             }
227         }
228
229         internalSetNeedsDisplay(&dirtyRect);
230     }
231     owner()->setNeedsCommit();
232 }
233
234 void PlatformCALayerWinInternal::setSublayers(const PlatformCALayerList& list)
235 {
236     // Remove all the current sublayers and add the passed layers
237     CACFLayerSetSublayers(owner()->platformLayer(), 0);
238
239     // Perform removeFromSuperLayer in a separate pass. CACF requires superlayer to
240     // be null or CACFLayerInsertSublayer silently fails.
241     for (size_t i = 0; i < list.size(); i++)
242         CACFLayerRemoveFromSuperlayer(list[i]->platformLayer());
243
244     for (size_t i = 0; i < list.size(); i++)
245         CACFLayerInsertSublayer(owner()->platformLayer(), list[i]->platformLayer(), i);
246
247     owner()->setNeedsCommit();
248
249     if (layerTypeIsTiled(m_owner->layerType())) {
250         // Preserve the tile parent after set
251         CACFLayerInsertSublayer(owner()->platformLayer(), m_tileParent.get(), 0);
252     }
253 }
254
255 void PlatformCALayerWinInternal::getSublayers(PlatformCALayerList& list) const
256 {
257     CFArrayRef sublayers = CACFLayerGetSublayers(owner()->platformLayer());
258     if (!sublayers) {
259         list.clear();
260         return;
261     }
262
263     size_t count = CFArrayGetCount(sublayers);
264
265     size_t layersToSkip = 0;
266     if (layerTypeIsTiled(m_owner->layerType())) {
267         // Exclude the tile parent layer.
268         layersToSkip = 1;
269     }
270
271     list.resize(count - layersToSkip);
272     for (size_t arrayIndex = layersToSkip; arrayIndex < count; ++arrayIndex)
273         list[arrayIndex - layersToSkip] = PlatformCALayer::platformCALayer(const_cast<void*>(CFArrayGetValueAtIndex(sublayers, arrayIndex)));
274 }
275
276 void PlatformCALayerWinInternal::removeAllSublayers()
277 {
278     CACFLayerSetSublayers(owner()->platformLayer(), 0);
279     owner()->setNeedsCommit();
280
281     if (layerTypeIsTiled(m_owner->layerType())) {
282         // Restore the tile parent after removal
283         CACFLayerInsertSublayer(owner()->platformLayer(), m_tileParent.get(), 0);
284     }
285 }
286
287 void PlatformCALayerWinInternal::insertSublayer(PlatformCALayer& layer, size_t index)
288 {
289     index = min(index, sublayerCount());
290     if (layerTypeIsTiled(m_owner->layerType())) {
291         // Add 1 to account for the tile parent layer
292         ++index;
293     }
294
295     layer.removeFromSuperlayer();
296     CACFLayerInsertSublayer(owner()->platformLayer(), layer.platformLayer(), index);
297     owner()->setNeedsCommit();
298 }
299
300 size_t PlatformCALayerWinInternal::sublayerCount() const
301 {
302     CFArrayRef sublayers = CACFLayerGetSublayers(owner()->platformLayer());
303     size_t count = sublayers ? CFArrayGetCount(sublayers) : 0;
304
305     if (layerTypeIsTiled(m_owner->layerType())) {
306         // Subtract 1 to account for the tile parent layer
307         ASSERT(count > 0);
308         count--;
309     }
310
311     return count;
312 }
313
314 int PlatformCALayerWinInternal::indexOfSublayer(const PlatformCALayer* reference)
315 {
316     CACFLayerRef ref = reference->platformLayer();
317     if (!ref)
318         return -1;
319
320     CFArrayRef sublayers = CACFLayerGetSublayers(owner()->platformLayer());
321     if (!sublayers)
322         return -1;
323
324     size_t n = CFArrayGetCount(sublayers);
325
326     if (layerTypeIsTiled(m_owner->layerType())) {
327         for (size_t i = 1; i < n; ++i) {
328             if (CFArrayGetValueAtIndex(sublayers, i) == ref)
329                 return i - 1;
330         }
331     } else {
332         for (size_t i = 0; i < n; ++i) {
333             if (CFArrayGetValueAtIndex(sublayers, i) == ref)
334                 return i;
335         }
336     }
337
338     return -1;
339 }
340
341 PlatformCALayer* PlatformCALayerWinInternal::sublayerAtIndex(int index) const
342 {
343     if (layerTypeIsTiled(m_owner->layerType())) {
344         // Add 1 to account for the tile parent layer
345         index++;
346     }
347
348     CFArrayRef sublayers = CACFLayerGetSublayers(owner()->platformLayer());
349     if (!sublayers || index < 0 || CFArrayGetCount(sublayers) <= index)
350         return 0;
351     
352     return PlatformCALayer::platformCALayer(static_cast<CACFLayerRef>(const_cast<void*>(CFArrayGetValueAtIndex(sublayers, index))));
353 }
354
355 void PlatformCALayerWinInternal::setBounds(const FloatRect& rect)
356 {
357     if (CGRectEqualToRect(rect, owner()->bounds()))
358         return;
359
360     CACFLayerSetBounds(owner()->platformLayer(), rect);
361     owner()->setNeedsCommit();
362
363     if (layerTypeIsTiled(m_owner->layerType())) {
364         m_constrainedSize = constrainedSize(rect.size());
365         updateTiles();
366     }
367 }
368
369 void PlatformCALayerWinInternal::setFrame(const FloatRect& rect)
370 {
371     CGRect oldFrame = CACFLayerGetFrame(owner()->platformLayer());
372     if (CGRectEqualToRect(rect, oldFrame))
373         return;
374
375     CACFLayerSetFrame(owner()->platformLayer(), rect);
376     owner()->setNeedsCommit();
377
378     if (layerTypeIsTiled(m_owner->layerType()))
379         updateTiles();
380 }
381
382 CGSize PlatformCALayerWinInternal::constrainedSize(const CGSize& size) const
383 {
384     const int cMaxTileCount = 512;
385     const float cSqrtMaxTileCount = sqrtf(cMaxTileCount);
386
387     CGSize constrainedSize = size;
388
389     int tileColumns = ceilf(constrainedSize.width / m_tileSize.width);
390     int tileRows = ceilf(constrainedSize.height / m_tileSize.height);
391
392     bool tooManyTiles = tileColumns && numeric_limits<int>::max() / tileColumns < tileRows || tileColumns * tileRows > cMaxTileCount;
393
394     // If number of tiles vertically or horizontally is < sqrt(cMaxTileCount)
395     // just shorten the longer dimension. Otherwise shorten both dimensions
396     // according to the ratio of width to height
397
398     if (tooManyTiles) {
399         if (tileRows < cSqrtMaxTileCount)
400             tileColumns = floorf(cMaxTileCount / tileRows);
401         else if (tileColumns < cSqrtMaxTileCount)
402             tileRows = floorf(cMaxTileCount / tileColumns);
403         else {
404             tileRows = ceilf(sqrtf(cMaxTileCount * constrainedSize.height / constrainedSize.width));
405             tileColumns = floorf(cMaxTileCount / tileRows);
406         }
407         
408         constrainedSize.width = tileColumns * m_tileSize.width;
409         constrainedSize.height = tileRows * m_tileSize.height;
410     }
411     
412     return constrainedSize;
413 }
414
415 void PlatformCALayerWinInternal::tileDisplayCallback(CACFLayerRef layer, CGContextRef context)
416 {
417     static_cast<PlatformCALayerWinInternal*>(CACFLayerGetUserData(layer))->drawTile(layer, context);
418 }
419
420 void PlatformCALayerWinInternal::addTile()
421 {
422     RetainPtr<CACFLayerRef> newLayer = adoptCF(CACFLayerCreate(kCACFLayer));
423     CACFLayerSetAnchorPoint(newLayer.get(), CGPointMake(0, 1));
424     CACFLayerSetUserData(newLayer.get(), this);
425     CACFLayerSetDisplayCallback(newLayer.get(), tileDisplayCallback);
426
427     CFArrayRef sublayers = CACFLayerGetSublayers(m_tileParent.get());
428     CACFLayerInsertSublayer(m_tileParent.get(), newLayer.get(), sublayers ? CFArrayGetCount(sublayers) : 0);
429
430     if (owner()->owner()->platformCALayerShowDebugBorders()) {
431         CGColorRef borderColor = CGColorCreateGenericRGB(0.5, 0, 0.5, 0.7);
432         CACFLayerSetBorderColor(newLayer.get(), borderColor);
433         CGColorRelease(borderColor);
434         CACFLayerSetBorderWidth(newLayer.get(), 2);
435     }
436 }
437
438 void PlatformCALayerWinInternal::removeTile()
439 {
440     CACFLayerRemoveFromSuperlayer(tileAtIndex(tileCount() - 1));
441 }
442
443 CACFLayerRef PlatformCALayerWinInternal::tileAtIndex(int index)
444 {
445     CFArrayRef sublayers = CACFLayerGetSublayers(m_tileParent.get());
446     if (!sublayers || index < 0 || index >= tileCount())
447         return 0;
448     
449     return static_cast<CACFLayerRef>(const_cast<void*>(CFArrayGetValueAtIndex(sublayers, index)));
450 }
451
452 int PlatformCALayerWinInternal::tileCount() const
453 {
454     CFArrayRef sublayers = CACFLayerGetSublayers(m_tileParent.get());
455     return sublayers ? CFArrayGetCount(sublayers) : 0;
456 }
457
458 void PlatformCALayerWinInternal::updateTiles()
459 {
460     // FIXME: In addition to redoing the number of tiles, we need to only render and have backing
461     // store for visible layers
462     int numTilesHorizontal = ceil(m_constrainedSize.width / m_tileSize.width);
463     int numTilesVertical = ceil(m_constrainedSize.height / m_tileSize.height);
464     int numTilesTotal = numTilesHorizontal * numTilesVertical;
465     ASSERT(!m_constrainedSize.height || !m_constrainedSize.width || numTilesTotal > 0);
466
467     int numTilesToChange = numTilesTotal - tileCount();
468     if (numTilesToChange >= 0) {
469         // Add new tiles
470         for (int i = 0; i < numTilesToChange; ++i)
471             addTile();
472     } else {
473         // Remove old tiles
474         numTilesToChange = -numTilesToChange;
475         for (int i = 0; i < numTilesToChange; ++i)
476             removeTile();
477     }
478
479     // Set coordinates for all tiles
480     CFArrayRef tileArray = CACFLayerGetSublayers(m_tileParent.get());
481
482     for (int i = 0; i < numTilesHorizontal; ++i) {
483         for (int j = 0; j < numTilesVertical; ++j) {
484             CACFLayerRef tile = static_cast<CACFLayerRef>(const_cast<void*>(CFArrayGetValueAtIndex(tileArray, i * numTilesVertical + j)));
485             CACFLayerSetPosition(tile, CGPointMake(i * m_tileSize.width, j * m_tileSize.height));
486             int width = min(m_tileSize.width, m_constrainedSize.width - i * m_tileSize.width);
487             int height = min(m_tileSize.height, m_constrainedSize.height - j * m_tileSize.height);
488             CACFLayerSetBounds(tile, CGRectMake(i * m_tileSize.width, j * m_tileSize.height, width, height));
489
490             // Flip Y to compensate for the flipping that happens during render to match the CG context coordinate space
491             CATransform3D transform = CATransform3DMakeScale(1, -1, 1);
492             CATransform3DTranslate(transform, 0, height, 0);
493             CACFLayerSetTransform(tile, transform);
494
495 #ifndef NDEBUG
496             String name = "Tile (" + String::number(i) + "," + String::number(j) + ")";
497             CACFLayerSetName(tile, name.createCFString().get());
498 #endif
499         }
500     }
501 }
502
503 void PlatformCALayerWinInternal::drawTile(CACFLayerRef tile, CGContextRef context)
504 {
505     CGPoint tilePosition = CACFLayerGetPosition(tile);
506     CGRect tileBounds = CACFLayerGetBounds(tile);
507
508     CGContextSaveGState(context);
509
510     // Transform context to be at the origin of the parent layer
511     CGContextTranslateCTM(context, -tilePosition.x, -tilePosition.y);
512
513     // Set the context clipping rectangle to the current tile
514     CGContextClipToRect(context, CGRectMake(tilePosition.x, tilePosition.y, tileBounds.size.width, tileBounds.size.height));
515
516     if (owner()->owner()->platformCALayerContentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) {
517         // If the layer is rendering top-down, it will flip the coordinates in y. Tiled layers are
518         // already flipping, so we need to undo that here.
519         CGContextTranslateCTM(context, 0, owner()->bounds().height());
520         CGContextScaleCTM(context, 1, -1);
521     }
522
523     // Draw the tile
524     displayCallback(owner()->platformLayer(), context);
525
526     CGContextRestoreGState(context);
527 }
528
529 TileController* PlatformCALayerWinInternal::createTileController(PlatformCALayer* rootLayer)
530 {
531     ASSERT(!m_tileController);
532     m_tileController = TileController::create(rootLayer);
533     return m_tileController.get();
534 }
535
536 TiledBacking* PlatformCALayerWinInternal::tiledBacking()
537 {
538     return m_tileController.get();
539 }