Merge "Save and re-bind previously bounded texture when using cairo_gl_surface_set_bi...
[framework/web/webkit-efl.git] / Source / WebKit2 / WebProcess / WebPage / LayerTreeCoordinator / LayerTreeCoordinator.cpp
1 /*
2  * Copyright (C) 2011 Apple Inc. All rights reserved.
3  * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24  * THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28
29 #include "LayerTreeCoordinator.h"
30
31 #include "CoordinatedGraphicsArgumentCoders.h"
32 #include "DrawingAreaImpl.h"
33 #include "GraphicsContext.h"
34 #include "LayerTreeCoordinatorProxyMessages.h"
35 #include "MessageID.h"
36 #include "SurfaceUpdateInfo.h"
37 #include "WebCoreArgumentCoders.h"
38 #include "WebGraphicsLayer.h"
39 #include "WebPage.h"
40 #include <WebCore/Frame.h>
41 #include <WebCore/FrameView.h>
42 #include <WebCore/Page.h>
43 #include <WebCore/RenderLayer.h>
44 #include <WebCore/RenderLayerBacking.h>
45 #include <WebCore/RenderLayerCompositor.h>
46 #include <WebCore/RenderView.h>
47 #include <WebCore/Settings.h>
48
49 #if ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
50 #include "WebProcess.h"
51 #endif
52
53 using namespace WebCore;
54
55 namespace WebKit {
56
57 #if ENABLE(TIZEN_LAYER_FLUSH_THROTTLING)
58 const float LayerTreeCoordinator::s_layerFlushTimerDelayTable[s_layerFlushTimerDelayMaxLevel] = {0, 0.1, 0.2, 0.6, 1.3};
59 #endif
60
61 PassRefPtr<LayerTreeCoordinator> LayerTreeCoordinator::create(WebPage* webPage)
62 {
63     return adoptRef(new LayerTreeCoordinator(webPage));
64 }
65
66 LayerTreeCoordinator::~LayerTreeCoordinator()
67 {
68     // Prevent setWebGraphicsLayerClient(0) -> detachLayer() from modifying the set while we iterate it.
69     HashSet<WebCore::WebGraphicsLayer*> registeredLayers;
70     registeredLayers.swap(m_registeredLayers);
71
72     HashSet<WebCore::WebGraphicsLayer*>::iterator end = registeredLayers.end();
73     for (HashSet<WebCore::WebGraphicsLayer*>::iterator it = registeredLayers.begin(); it != end; ++it)
74         (*it)->setWebGraphicsLayerClient(0);
75 }
76
77 LayerTreeCoordinator::LayerTreeCoordinator(WebPage* webPage)
78     : LayerTreeHost(webPage)
79     , m_notifyAfterScheduledLayerFlush(false)
80     , m_isValid(true)
81 #if OS(TIZEN)
82     , m_waitingForUIProcess(false)
83 #else
84     , m_waitingForUIProcess(true)
85 #endif
86     , m_isSuspended(false)
87     , m_contentsScale(1)
88     , m_shouldSendScrollPositionUpdate(true)
89     , m_shouldSyncFrame(false)
90     , m_shouldSyncRootLayer(true)
91     , m_layerFlushTimer(this, &LayerTreeCoordinator::layerFlushTimerFired)
92     , m_releaseInactiveAtlasesTimer(this, &LayerTreeCoordinator::releaseInactiveAtlasesTimerFired)
93     , m_layerFlushSchedulingEnabled(true)
94 #if ENABLE(TIZEN_LAYER_FLUSH_THROTTLING)
95     , m_layerFlushTimerDelay(0.0)
96     , m_deferLayerFlushEnabled(false)
97     , m_layerFlushTimerDelayLevel(0)
98 #endif
99 #if ENABLE(TIZEN_WEBKIT2_TILED_AC)
100     , m_suspendedJavaScript(false)
101 #endif
102 #if ENABLE(TIZEN_RECORDING_SURFACE_SET)
103     , m_compositedContentLayersCount(0)
104 #endif
105 #if ENABLE(TIZEN_ONESHOT_DRAWING_SYNCHRONIZATION)
106     , m_needsOneShotDrawingSynchronization(false)
107 #endif
108     , m_animationsLocked(false)
109 #if ENABLE(TIZEN_RUNTIME_BACKEND_SELECTION)
110     , m_isGLAccelerationMode(true)
111 #endif
112 {
113     // Create a root layer.
114     m_rootLayer = GraphicsLayer::create(this);
115     WebGraphicsLayer* webRootLayer = toWebGraphicsLayer(m_rootLayer.get());
116     webRootLayer->setRootLayer(true);
117 #ifndef NDEBUG
118     m_rootLayer->setName("LayerTreeCoordinator root layer");
119 #endif
120     m_rootLayer->setDrawsContent(false);
121     m_rootLayer->setSize(m_webPage->size());
122     m_layerTreeContext.webLayerID = toWebGraphicsLayer(webRootLayer)->id();
123
124     m_nonCompositedContentLayer = GraphicsLayer::create(this);
125 #if ENABLE(TIZEN_RECORDING_SURFACE_SET)
126     WebGraphicsLayer* webNonCompositedLayer = toWebGraphicsLayer(m_nonCompositedContentLayer.get());
127     webNonCompositedLayer->setNonCompositedLayer(true);
128 #endif
129
130     toWebGraphicsLayer(m_rootLayer.get())->setWebGraphicsLayerClient(this);
131 #ifndef NDEBUG
132     m_nonCompositedContentLayer->setName("LayerTreeCoordinator non-composited content");
133 #endif
134     m_nonCompositedContentLayer->setDrawsContent(true);
135     m_nonCompositedContentLayer->setSize(m_webPage->size());
136
137     m_rootLayer->addChild(m_nonCompositedContentLayer.get());
138
139     if (m_webPage->hasPageOverlay())
140         createPageOverlayLayer();
141
142     scheduleLayerFlush();
143 }
144
145 void LayerTreeCoordinator::setLayerFlushSchedulingEnabled(bool layerFlushingEnabled)
146 {
147     if (m_layerFlushSchedulingEnabled == layerFlushingEnabled)
148         return;
149
150     m_layerFlushSchedulingEnabled = layerFlushingEnabled;
151
152     if (m_layerFlushSchedulingEnabled) {
153         scheduleLayerFlush();
154         return;
155     }
156
157     cancelPendingLayerFlush();
158 }
159
160 void LayerTreeCoordinator::scheduleLayerFlush()
161 {
162     if (!m_layerFlushSchedulingEnabled)
163         return;
164
165     if (!m_layerFlushTimer.isActive()) {
166 #if ENABLE(TIZEN_LAYER_FLUSH_THROTTLING)
167         m_layerFlushTimerDelay = deferredLayerFlushDelay();
168         m_layerFlushTimer.startOneShot(m_layerFlushTimerDelay);
169     }
170 #if ENABLE(TIZEN_SYNC_REQUEST_ANIMATION_FRAME)
171     if (m_layerFlushTimerDelay > 0.0)
172         m_webPage->suspendAnimationController();
173 #endif
174 #else
175         m_layerFlushTimer.startOneShot(0.0);
176     }
177 #endif
178
179 #if ENABLE(TIZEN_WEBKIT2_ROTATION_WHILE_JAVASCRIPT_POPUP)
180     if (!m_layerFlushWorkItemToDispatchWhileWaitingForSyncReply)
181         m_layerFlushWorkItemToDispatchWhileWaitingForSyncReply = m_webPage->connection()->dispatchWorkItemWhileWaitingForSyncReply(WTF::bind(&LayerTreeCoordinator::performScheduledLayerFlushForcely, this));
182 #endif
183 }
184
185 void LayerTreeCoordinator::cancelPendingLayerFlush()
186 {
187     m_layerFlushTimer.stop();
188 #if ENABLE(TIZEN_WEBKIT2_ROTATION_WHILE_JAVASCRIPT_POPUP)
189     m_webPage->connection()->clearWorkItemWhileWaitingForSyncReply(m_layerFlushWorkItemToDispatchWhileWaitingForSyncReply);
190     m_layerFlushWorkItemToDispatchWhileWaitingForSyncReply.clear();
191 #endif
192 }
193
194 void LayerTreeCoordinator::setShouldNotifyAfterNextScheduledLayerFlush(bool notifyAfterScheduledLayerFlush)
195 {
196     m_notifyAfterScheduledLayerFlush = notifyAfterScheduledLayerFlush;
197 }
198
199 void LayerTreeCoordinator::setRootCompositingLayer(WebCore::GraphicsLayer* graphicsLayer)
200 {
201     m_nonCompositedContentLayer->removeAllChildren();
202     m_nonCompositedContentLayer->setContentsOpaque(m_webPage->drawsBackground() && !m_webPage->drawsTransparentBackground());
203
204     // Add the accelerated layer tree hierarchy.
205     if (graphicsLayer)
206         m_nonCompositedContentLayer->addChild(graphicsLayer);
207
208 #if ENABLE(TIZEN_RECORDING_SURFACE_SET)
209     m_compositedContentLayersCount = compositedContentLayersCount(m_nonCompositedContentLayer.get());
210 #endif
211 }
212
213 void LayerTreeCoordinator::invalidate()
214 {
215     cancelPendingLayerFlush();
216
217     ASSERT(m_isValid);
218     m_rootLayer = nullptr;
219     m_isValid = false;
220 }
221
222 void LayerTreeCoordinator::setNonCompositedContentsNeedDisplay(const WebCore::IntRect& rect)
223 {
224     m_nonCompositedContentLayer->setNeedsDisplayInRect(rect);
225     if (m_pageOverlayLayer)
226         m_pageOverlayLayer->setNeedsDisplayInRect(rect);
227
228     scheduleLayerFlush();
229 }
230
231 void LayerTreeCoordinator::scrollNonCompositedContents(const WebCore::IntRect& scrollRect, const WebCore::IntSize& scrollOffset)
232 {
233     setNonCompositedContentsNeedDisplay(scrollRect);
234 }
235
236 void LayerTreeCoordinator::forceRepaint()
237 {
238     // We need to schedule another flush, otherwise the forced paint might cancel a later expected flush.
239     // This is aligned with LayerTreeHostCA.
240     scheduleLayerFlush();
241     flushPendingLayerChanges();
242 }
243
244 void LayerTreeCoordinator::sizeDidChange(const WebCore::IntSize& newSize)
245 {
246     if (m_rootLayer->size() == newSize)
247         return;
248
249     m_rootLayer->setSize(newSize);
250
251     // If the newSize exposes new areas of the non-composited content a setNeedsDisplay is needed
252     // for those newly exposed areas.
253     FloatSize oldSize = m_nonCompositedContentLayer->size();
254     m_nonCompositedContentLayer->setSize(newSize);
255
256     if (newSize.width() > oldSize.width()) {
257         float height = std::min(static_cast<float>(newSize.height()), oldSize.height());
258         m_nonCompositedContentLayer->setNeedsDisplayInRect(FloatRect(oldSize.width(), 0, newSize.width() - oldSize.width(), height));
259     }
260
261     if (newSize.height() > oldSize.height())
262         m_nonCompositedContentLayer->setNeedsDisplayInRect(FloatRect(0, oldSize.height(), newSize.width(), newSize.height() - oldSize.height()));
263
264     if (m_pageOverlayLayer)
265         m_pageOverlayLayer->setSize(newSize);
266
267     scheduleLayerFlush();
268 }
269
270 void LayerTreeCoordinator::didInstallPageOverlay()
271 {
272     createPageOverlayLayer();
273     scheduleLayerFlush();
274 }
275
276 void LayerTreeCoordinator::didUninstallPageOverlay()
277 {
278     destroyPageOverlayLayer();
279     scheduleLayerFlush();
280 }
281
282 void LayerTreeCoordinator::setPageOverlayNeedsDisplay(const WebCore::IntRect& rect)
283 {
284     ASSERT(m_pageOverlayLayer);
285     m_pageOverlayLayer->setNeedsDisplayInRect(rect);
286     scheduleLayerFlush();
287 }
288
289 void LayerTreeCoordinator::setPageOverlayOpacity(float value)
290 {
291     ASSERT(m_pageOverlayLayer);
292     m_pageOverlayLayer->setOpacity(value);
293     scheduleLayerFlush();
294 }
295
296 bool LayerTreeCoordinator::flushPendingLayerChanges()
297 {
298     if (m_waitingForUIProcess)
299         return false;
300
301     bool didSync = m_webPage->corePage()->mainFrame()->view()->syncCompositingStateIncludingSubframes();
302     m_nonCompositedContentLayer->syncCompositingStateForThisLayerOnly();
303     if (m_pageOverlayLayer)
304         m_pageOverlayLayer->syncCompositingStateForThisLayerOnly();
305
306     m_rootLayer->syncCompositingStateForThisLayerOnly();
307
308     if (m_shouldSyncRootLayer) {
309         m_webPage->send(Messages::LayerTreeCoordinatorProxy::SetRootCompositingLayer(toWebGraphicsLayer(m_rootLayer.get())->id()));
310         m_shouldSyncRootLayer = false;
311     }
312
313     if (!m_shouldSyncFrame)
314         return didSync;
315
316 #if ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
317     if (!m_compositedContentLayers.isEmpty()) {
318         Vector<uint32_t> weblayerIDsCopy;
319         copyToVector(m_compositedContentLayers, weblayerIDsCopy);
320         m_compositedContentLayers.clear();
321         bool pauseJavaScript = false;
322         for (size_t i = 0; i < weblayerIDsCopy.size(); ++i) {
323             WebGraphicsLayer* layer = WebGraphicsLayer::layerByID(weblayerIDsCopy[i]);
324             if (layer && !layer->swapPlatformSurfaces())
325                 pauseJavaScript = true;
326         }
327         if (pauseJavaScript) {
328             m_webPage->suspendJavaScriptAndResources();
329             m_suspendedJavaScript = true;
330         }
331     }
332 #endif
333
334 #if ENABLE(TIZEN_SYNC_REQUEST_ANIMATION_FRAME)
335     m_webPage->suspendAnimationController();
336 #endif
337     m_webPage->send(Messages::LayerTreeCoordinatorProxy::DidRenderFrame());
338     m_waitingForUIProcess = true;
339     m_shouldSyncFrame = false;
340
341     return true;
342 }
343
344 void LayerTreeCoordinator::syncLayerState(WebLayerID id, const WebLayerInfo& info)
345 {
346     if (m_shouldSendScrollPositionUpdate) {
347         m_webPage->send(Messages::LayerTreeCoordinatorProxy::DidChangeScrollPosition(m_visibleContentsRect.location()));
348         m_shouldSendScrollPositionUpdate = false;
349     }
350
351     m_shouldSyncFrame = true;
352     m_webPage->send(Messages::LayerTreeCoordinatorProxy::SetCompositingLayerState(id, info));
353 }
354
355 void LayerTreeCoordinator::syncLayerChildren(WebLayerID id, const Vector<WebLayerID>& children)
356 {
357     m_shouldSyncFrame = true;
358     m_webPage->send(Messages::LayerTreeCoordinatorProxy::SetCompositingLayerChildren(id, children));
359 }
360
361 #if ENABLE(TIZEN_WEBKIT2_TILED_AC)
362 void LayerTreeCoordinator::syncCanvas(WebLayerID id, const IntSize& canvasSize, uint64_t graphicsSurfaceToken, uint32_t frontBuffer, int flags)
363 #else
364 void LayerTreeCoordinator::syncCanvas(WebLayerID id, const IntSize& canvasSize, uint64_t graphicsSurfaceToken, uint32_t frontBuffer)
365 #endif
366 {
367     m_shouldSyncFrame = true;
368 #if ENABLE(TIZEN_WEBKIT2_TILED_AC)
369     m_compositedContentLayers.add(id);
370 #if ENABLE(TIZEN_ACCELERATED_2D_CANVAS_EFL)
371     m_compositedContentCanvas2DLayers.add(id);
372 #endif
373     m_webPage->send(Messages::LayerTreeCoordinatorProxy::SyncCanvas(id, canvasSize, graphicsSurfaceToken, frontBuffer, flags));
374 #else
375     m_webPage->send(Messages::LayerTreeCoordinatorProxy::SyncCanvas(id, canvasSize, graphicsSurfaceToken, frontBuffer));
376 #endif
377 }
378
379 #if ENABLE(CSS_FILTERS)
380 void LayerTreeCoordinator::syncLayerFilters(WebLayerID id, const FilterOperations& filters)
381 {
382     m_shouldSyncFrame = true;
383     m_webPage->send(Messages::LayerTreeCoordinatorProxy::SetCompositingLayerFilters(id, filters));
384 }
385 #endif
386
387 void LayerTreeCoordinator::attachLayer(WebGraphicsLayer* layer)
388 {
389     ASSERT(!m_registeredLayers.contains(layer));
390     m_registeredLayers.add(layer);
391
392     layer->setContentsScale(m_contentsScale);
393     layer->adjustVisibleRect();
394
395 #if ENABLE(TIZEN_RECORDING_SURFACE_SET)
396     m_compositedContentLayersCount = compositedContentLayersCount(m_nonCompositedContentLayer.get());
397 #endif
398 }
399
400 void LayerTreeCoordinator::detachLayer(WebGraphicsLayer* layer)
401 {
402     m_registeredLayers.remove(layer);
403     m_shouldSyncFrame = true;
404     m_webPage->send(Messages::LayerTreeCoordinatorProxy::DeleteCompositingLayer(layer->id()));
405
406 #if ENABLE(TIZEN_RECORDING_SURFACE_SET)
407     m_compositedContentLayersCount = compositedContentLayersCount(m_nonCompositedContentLayer.get());
408 #endif
409
410 #if ENABLE(TIZEN_WEBKIT2_TILED_AC)
411     m_compositedContentLayers.remove(layer->id());
412 #endif
413 #if ENABLE(TIZEN_ACCELERATED_2D_CANVAS_EFL)
414     m_compositedContentCanvas2DLayers.remove(layer->id());
415 #endif
416 }
417
418 static void updateOffsetFromViewportForSelf(RenderLayer* renderLayer)
419 {
420     // These conditions must match the conditions in RenderLayerCompositor::requiresCompositingForPosition.
421     RenderLayerBacking* backing = renderLayer->backing();
422     if (!backing)
423         return;
424
425     RenderStyle* style = renderLayer->renderer()->style();
426     if (!style)
427         return;
428
429     if (!renderLayer->renderer()->isOutOfFlowPositioned() || renderLayer->renderer()->style()->position() != FixedPosition)
430         return;
431
432     if (!renderLayer->renderer()->container()->isRenderView())
433         return;
434
435     if (!renderLayer->isStackingContext())
436         return;
437
438     WebGraphicsLayer* graphicsLayer = toWebGraphicsLayer(backing->graphicsLayer());
439     graphicsLayer->setFixedToViewport(true);
440 }
441
442 static void updateOffsetFromViewportForLayer(RenderLayer* renderLayer)
443 {
444     updateOffsetFromViewportForSelf(renderLayer);
445
446     if (renderLayer->firstChild())
447         updateOffsetFromViewportForLayer(renderLayer->firstChild());
448     if (renderLayer->nextSibling())
449         updateOffsetFromViewportForLayer(renderLayer->nextSibling());
450 }
451
452 void LayerTreeCoordinator::syncFixedLayers()
453 {
454     if (!m_webPage->corePage()->settings() || !m_webPage->corePage()->settings()->acceleratedCompositingForFixedPositionEnabled())
455         return;
456
457     if (!m_webPage->mainFrame()->view()->hasFixedObjects())
458         return;
459
460     RenderLayer* rootRenderLayer = m_webPage->mainFrame()->contentRenderer()->compositor()->rootRenderLayer();
461     ASSERT(rootRenderLayer);
462     if (rootRenderLayer->firstChild())
463         updateOffsetFromViewportForLayer(rootRenderLayer->firstChild());
464 }
465
466 void LayerTreeCoordinator::lockAnimations()
467 {
468     m_animationsLocked = true;
469     m_webPage->send(Messages::LayerTreeCoordinatorProxy::SetAnimationsLocked(true));
470 }
471
472 void LayerTreeCoordinator::unlockAnimations()
473 {
474     if (!m_animationsLocked)
475         return;
476
477     m_animationsLocked = false;
478     m_webPage->send(Messages::LayerTreeCoordinatorProxy::SetAnimationsLocked(false));
479 }
480
481 void LayerTreeCoordinator::performScheduledLayerFlush()
482 {
483 #if ENABLE(TIZEN_ACCELERATED_2D_CANVAS_EFL)
484     if (m_waitingForUIProcess && !m_compositedContentCanvas2DLayers.isEmpty()) {
485         Vector<uint32_t> weblayerIDsCopy;
486         copyToVector(m_compositedContentCanvas2DLayers, weblayerIDsCopy);
487         m_compositedContentCanvas2DLayers.clear();
488         for (size_t i = 0; i < weblayerIDsCopy.size(); ++i) {
489             WebGraphicsLayer* layer = WebGraphicsLayer::layerByID(weblayerIDsCopy[i]);
490             if (layer)
491                 layer->flushPlatformSurfaces();
492         }
493         return;
494     }
495 #endif
496
497     if (m_isSuspended || m_waitingForUIProcess)
498         return;
499
500 #if ENABLE(TIZEN_CUTOFF_TILES_OVER_MEMORY_LIMIT)
501     calculateCutOffThreshold();
502 #endif
503
504 #if ENABLE(REQUEST_ANIMATION_FRAME) && !USE(REQUEST_ANIMATION_FRAME_TIMER) && !USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
505     // Make sure that any previously registered animation callbacks are being executed before we flush the layers.
506     m_webPage->corePage()->mainFrame()->view()->serviceScriptedAnimations(convertSecondsToDOMTimeStamp(currentTime()));
507 #endif
508
509     // We lock the animations while performing layout, to avoid flickers caused by animations continuing in the UI process while
510     // the web process layout wants to cancel them.
511     lockAnimations();
512
513     m_webPage->layoutIfNeeded();
514
515     // We can unlock the animations before flushing if there are no visible changes, for example if there are content updates
516     // in a layer with opacity 0.
517     bool canUnlockBeforeFlush = !m_isValid || !toWebGraphicsLayer(m_rootLayer.get())->hasPendingVisibleChanges();
518     if (canUnlockBeforeFlush)
519         unlockAnimations();
520
521     if (!m_isValid)
522         return;
523
524 #if ENABLE(TIZEN_ONESHOT_DRAWING_SYNCHRONIZATION)
525     if (m_needsOneShotDrawingSynchronization) {
526         scheduleLayerFlush();
527         toWebGraphicsLayer(m_nonCompositedContentLayer.get())->adjustVisibleRect();
528         m_needsOneShotDrawingSynchronization = false;
529         return;
530     }
531 #endif
532
533     if (flushPendingLayerChanges())
534         didPerformScheduledLayerFlush();
535 }
536
537 void LayerTreeCoordinator::didPerformScheduledLayerFlush()
538 {
539     if (m_notifyAfterScheduledLayerFlush) {
540         static_cast<DrawingAreaImpl*>(m_webPage->drawingArea())->layerHostDidFlushLayers();
541         m_notifyAfterScheduledLayerFlush = false;
542     }
543 }
544
545 void LayerTreeCoordinator::layerFlushTimerFired(Timer<LayerTreeCoordinator>*)
546 {
547 #if ENABLE(TIZEN_WEBKIT2_ROTATION_WHILE_JAVASCRIPT_POPUP)
548     m_webPage->connection()->clearWorkItemWhileWaitingForSyncReply(m_layerFlushWorkItemToDispatchWhileWaitingForSyncReply);
549     m_layerFlushWorkItemToDispatchWhileWaitingForSyncReply.clear();
550 #endif
551     performScheduledLayerFlush();
552 }
553
554 void LayerTreeCoordinator::createPageOverlayLayer()
555 {
556     ASSERT(!m_pageOverlayLayer);
557
558     m_pageOverlayLayer = GraphicsLayer::create(this);
559 #ifndef NDEBUG
560     m_pageOverlayLayer->setName("LayerTreeCoordinator page overlay content");
561 #endif
562
563     m_pageOverlayLayer->setDrawsContent(true);
564     m_pageOverlayLayer->setSize(m_webPage->size());
565
566     m_rootLayer->addChild(m_pageOverlayLayer.get());
567 }
568
569 void LayerTreeCoordinator::destroyPageOverlayLayer()
570 {
571     ASSERT(m_pageOverlayLayer);
572     m_pageOverlayLayer->removeFromParent();
573     m_pageOverlayLayer = nullptr;
574 }
575
576 int64_t LayerTreeCoordinator::adoptImageBackingStore(Image* image)
577 {
578     if (!image)
579         return InvalidWebLayerID;
580
581     int64_t key = 0;
582
583 #if PLATFORM(QT)
584     QImage* nativeImage = image->nativeImageForCurrentFrame();
585
586     if (!nativeImage)
587         return InvalidWebLayerID;
588
589     key = nativeImage->cacheKey();
590 #elif ENABLE(TIZEN_WEBKIT2_TILED_AC)
591     key = (int64_t)(image);
592 #endif
593
594     HashMap<int64_t, int>::iterator it = m_directlyCompositedImageRefCounts.find(key);
595
596     if (it != m_directlyCompositedImageRefCounts.end()) {
597         ++(it->second);
598         return key;
599     }
600
601     RefPtr<ShareableBitmap> bitmap = ShareableBitmap::createShareable(image->size(), (image->currentFrameHasAlpha() ? ShareableBitmap::SupportsAlpha : 0));
602     {
603         OwnPtr<WebCore::GraphicsContext> graphicsContext = bitmap->createGraphicsContext();
604         graphicsContext->drawImage(image, ColorSpaceDeviceRGB, IntPoint::zero());
605     }
606
607     ShareableBitmap::Handle handle;
608     bitmap->createHandle(handle);
609     m_webPage->send(Messages::LayerTreeCoordinatorProxy::CreateDirectlyCompositedImage(key, handle));
610     m_directlyCompositedImageRefCounts.add(key, 1);
611     return key;
612 }
613
614 void LayerTreeCoordinator::releaseImageBackingStore(int64_t key)
615 {
616     if (!key)
617         return;
618     HashMap<int64_t, int>::iterator it = m_directlyCompositedImageRefCounts.find(key);
619     if (it == m_directlyCompositedImageRefCounts.end())
620         return;
621
622     it->second--;
623
624     if (it->second)
625         return;
626
627     m_directlyCompositedImageRefCounts.remove(it);
628     m_webPage->send(Messages::LayerTreeCoordinatorProxy::DestroyDirectlyCompositedImage(key));
629 }
630
631
632 void LayerTreeCoordinator::notifyAnimationStarted(const WebCore::GraphicsLayer*, double time)
633 {
634 }
635
636 void LayerTreeCoordinator::notifySyncRequired(const WebCore::GraphicsLayer*)
637 {
638 }
639
640 void LayerTreeCoordinator::paintContents(const WebCore::GraphicsLayer* graphicsLayer, WebCore::GraphicsContext& graphicsContext, WebCore::GraphicsLayerPaintingPhase, const WebCore::IntRect& clipRect)
641 {
642     if (graphicsLayer == m_nonCompositedContentLayer) {
643         m_webPage->drawRect(graphicsContext, clipRect);
644         return;
645     }
646
647     if (graphicsLayer == m_pageOverlayLayer) {
648         // Overlays contain transparent contents and won't clear the context as part of their rendering, so we do it here.
649         graphicsContext.clearRect(clipRect);
650         m_webPage->drawPageOverlay(graphicsContext, clipRect);
651         return;
652     }
653 }
654
655 bool LayerTreeCoordinator::showDebugBorders(const WebCore::GraphicsLayer*) const
656 {
657     return m_webPage->corePage()->settings()->showDebugBorders();
658 }
659
660 bool LayerTreeCoordinator::showRepaintCounter(const WebCore::GraphicsLayer*) const
661 {
662     return m_webPage->corePage()->settings()->showRepaintCounter();
663 }
664
665 bool LayerTreeHost::supportsAcceleratedCompositing()
666 {
667     return true;
668 }
669
670 void LayerTreeCoordinator::createTile(WebLayerID layerID, int tileID, const SurfaceUpdateInfo& updateInfo, const WebCore::IntRect& targetRect)
671 {
672     m_shouldSyncFrame = true;
673     m_webPage->send(Messages::LayerTreeCoordinatorProxy::CreateTileForLayer(layerID, tileID, targetRect, updateInfo));
674 }
675
676 void LayerTreeCoordinator::updateTile(WebLayerID layerID, int tileID, const SurfaceUpdateInfo& updateInfo, const WebCore::IntRect& targetRect)
677 {
678     m_shouldSyncFrame = true;
679     m_webPage->send(Messages::LayerTreeCoordinatorProxy::UpdateTileForLayer(layerID, tileID, targetRect, updateInfo));
680 }
681
682 void LayerTreeCoordinator::removeTile(WebLayerID layerID, int tileID)
683 {
684     m_shouldSyncFrame = true;
685     m_webPage->send(Messages::LayerTreeCoordinatorProxy::RemoveTileForLayer(layerID, tileID));
686 }
687
688 WebCore::IntRect LayerTreeCoordinator::visibleContentsRect() const
689 {
690     return m_visibleContentsRect;
691 }
692
693 void LayerTreeCoordinator::setLayerAnimations(WebLayerID layerID, const GraphicsLayerAnimations& animations)
694 {
695     m_shouldSyncFrame = true;
696     m_webPage->send(Messages::LayerTreeCoordinatorProxy::SetLayerAnimations(layerID, animations.getActiveAnimations()));
697 }
698
699 void LayerTreeCoordinator::setVisibleContentsRect(const IntRect& rect, float scale, const FloatPoint& trajectoryVector)
700 {
701     bool contentsRectDidChange = rect != m_visibleContentsRect;
702     bool contentsScaleDidChange = scale != m_contentsScale;
703
704     if (trajectoryVector != FloatPoint::zero())
705         toWebGraphicsLayer(m_nonCompositedContentLayer.get())->setVisibleContentRectTrajectoryVector(trajectoryVector);
706
707     if (contentsRectDidChange || contentsScaleDidChange) {
708         m_visibleContentsRect = rect;
709         m_contentsScale = scale;
710
711         HashSet<WebCore::WebGraphicsLayer*>::iterator end = m_registeredLayers.end();
712         for (HashSet<WebCore::WebGraphicsLayer*>::iterator it = m_registeredLayers.begin(); it != end; ++it) {
713             if (contentsScaleDidChange)
714                 (*it)->setContentsScale(scale);
715             if (contentsRectDidChange)
716 #if ENABLE(TIZEN_WEBKIT2_PRE_RENDERING_WITH_DIRECTIVITY)
717                 (*it)->setVisibleContentRectTrajectoryVector(trajectoryVector);
718 #else
719                 (*it)->adjustVisibleRect();
720 #endif
721         }
722     }
723
724     scheduleLayerFlush();
725     if (m_webPage->useFixedLayout())
726         m_webPage->setFixedVisibleContentRect(rect);
727     if (contentsRectDidChange)
728         m_shouldSendScrollPositionUpdate = true;
729 }
730
731 #if USE(UI_SIDE_COMPOSITING)
732 void LayerTreeCoordinator::scheduleAnimation()
733 {
734     scheduleLayerFlush();
735 }
736 #endif
737
738 void LayerTreeCoordinator::renderNextFrame()
739 {
740     m_waitingForUIProcess = false;
741 #if ENABLE(TIZEN_SYNC_REQUEST_ANIMATION_FRAME)
742 #if ENABLE(TIZEN_LAYER_FLUSH_THROTTLING)
743     if (m_layerFlushTimerDelay <= 0.0)
744 #endif
745         m_webPage->resumeAnimationController();
746 #endif
747     scheduleLayerFlush();
748     for (int i = 0; i < m_updateAtlases.size(); ++i)
749         m_updateAtlases[i]->didSwapBuffers();
750
751 #if ENABLE(TIZEN_SYNC_REQUEST_ANIMATION_FRAME)
752 #if ENABLE(TIZEN_LAYER_FLUSH_THROTTLING)
753     if (m_layerFlushTimerDelay > 0.0)
754         m_webPage->resumeAnimationController();
755 #endif
756 #endif
757 }
758
759 #if ENABLE(TIZEN_WEBKIT2_ROTATION_WHILE_JAVASCRIPT_POPUP)
760 void LayerTreeCoordinator::performScheduledLayerFlushForcely()
761 {
762     if (!WebProcess::shared().isWaitingForJavaScriptPopupFinished())
763         return;
764
765     m_layerFlushTimer.stop();
766     m_webPage->connection()->clearWorkItemWhileWaitingForSyncReply(m_layerFlushWorkItemToDispatchWhileWaitingForSyncReply);
767     m_layerFlushWorkItemToDispatchWhileWaitingForSyncReply.clear();
768
769     m_waitingForUIProcess = false;
770
771     performScheduledLayerFlush();
772 }
773 #endif
774
775 bool LayerTreeCoordinator::layerTreeTileUpdatesAllowed() const
776 {
777     return !m_isSuspended && !m_waitingForUIProcess;
778 }
779
780 void LayerTreeCoordinator::purgeBackingStores()
781 {
782     HashSet<WebCore::WebGraphicsLayer*>::iterator end = m_registeredLayers.end();
783     for (HashSet<WebCore::WebGraphicsLayer*>::iterator it = m_registeredLayers.begin(); it != end; ++it)
784         (*it)->purgeBackingStores();
785
786     ASSERT(!m_directlyCompositedImageRefCounts.size());
787     m_updateAtlases.clear();
788 }
789
790 PassOwnPtr<WebCore::GraphicsContext> LayerTreeCoordinator::beginContentUpdate(const WebCore::IntSize& size, ShareableBitmap::Flags flags, ShareableSurface::Handle& handle, WebCore::IntPoint& offset)
791 {
792     OwnPtr<WebCore::GraphicsContext> graphicsContext;
793     for (int i = 0; i < m_updateAtlases.size(); ++i) {
794         UpdateAtlas* atlas = m_updateAtlases[i].get();
795         if (atlas->flags() == flags) {
796             // This will return null if there is no available buffer space.
797             graphicsContext = atlas->beginPaintingOnAvailableBuffer(handle, size, offset);
798             if (graphicsContext)
799                 return graphicsContext.release();
800         }
801     }
802
803     static const int ScratchBufferDimension = 1024;
804     m_updateAtlases.append(adoptPtr(new UpdateAtlas(ScratchBufferDimension, flags)));
805     scheduleReleaseInactiveAtlases();
806     return m_updateAtlases.last()->beginPaintingOnAvailableBuffer(handle, size, offset);
807 }
808
809 #if ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
810 void LayerTreeCoordinator::freePlatformSurface(int layerID, int platformSurfaceId)
811 {
812     WebGraphicsLayer* layer = WebGraphicsLayer::layerByID(layerID);
813     if (layer && (layer->contentType() == WebLayerInfo::Canvas3DContentType || layer->contentType() == WebLayerInfo::MediaContentType || layer->contentType() == WebLayerInfo::Canvas2DContentType)) {
814         layer->freePlatformSurface(platformSurfaceId);
815
816         if (m_suspendedJavaScript && layer->swapPlatformSurfaces()) {
817             m_webPage->resumeJavaScriptAndResources();
818             m_suspendedJavaScript = false;
819         }
820     }
821
822     // Even after a graphics layer just destroyed in WebProcess side,
823     // freePlatformSurface messages that destroyed layer can surely come.
824     // Therefore, below code should be run always before layer validity check.
825     WebProcess::shared().platformSurfacePool()->freePlatformSurface(platformSurfaceId);
826 }
827
828 void LayerTreeCoordinator::freePlatformSurfaceByTileID(int tileID)
829 {
830     WebProcess::shared().platformSurfacePool()->freePlatformSurfaceByTileID(tileID);
831 }
832
833 void LayerTreeCoordinator::removePlatformSurface(int layerID, int platformSurfaceId)
834 {
835     WebGraphicsLayer* layer = WebGraphicsLayer::layerByID(layerID);
836     if (layer && (layer->contentType() == WebLayerInfo::Canvas3DContentType || layer->contentType() == WebLayerInfo::MediaContentType || layer->contentType() == WebLayerInfo::Canvas2DContentType))
837         layer->removePlatformSurface(platformSurfaceId);
838 }
839 #endif
840
841 #if ENABLE(TIZEN_RECORDING_SURFACE_SET)
842 bool LayerTreeCoordinator::recordingSurfaceSetEnableGet()
843 {
844     return recordingSurfaceAllowed() && m_webPage->recordingSurfaceEnabled();
845 }
846
847 bool LayerTreeCoordinator::recordingSurfaceSetLoadStartGet()
848 {
849     if (m_webPage->recordingSurfaceLoadStart()) {
850         m_webPage->setRecordingSurfaceLoadStart(false);
851         return true;
852     }
853     return false;
854 }
855
856 bool LayerTreeCoordinator::recordingSurfaceSetLoadFinishedGet()
857 {
858     if (m_webPage->recordingSurfaceLoadFinish()) {
859         m_webPage->setRecordingSurfaceLoadFinish(false);
860         return true;
861     }
862     return false;
863 }
864
865 bool LayerTreeCoordinator::recordingSurfaceAllowed()
866 {
867     if (m_compositedContentLayersCount > 0)
868         return false;
869
870     return true;
871 }
872
873 int LayerTreeCoordinator::compositedContentLayersCount(GraphicsLayer* layer)
874 {
875     int count = 0;
876     int contentType = toWebGraphicsLayer(layer)->contentType();
877
878     if (contentType == WebLayerInfo::Canvas3DContentType || contentType == WebLayerInfo::MediaContentType || contentType == WebLayerInfo::Canvas2DContentType)
879         count = 1;
880
881     const Vector<GraphicsLayer*>& childLayers = layer->children();
882     for (int i = 0; i < childLayers.size(); ++i)
883         count += compositedContentLayersCount(childLayers[i]);
884
885     return count;
886 }
887 #endif
888
889 #if ENABLE(TIZEN_CSS_OVERFLOW_SCROLL_ACCELERATION_ON_UI_SIDE)
890 void LayerTreeCoordinator::setVisibleContentsRectAndTrajectoryVectorForLayer(int layerID, const WebCore::IntRect& visibleRect, const WebCore::FloatPoint& trajectoryVector)
891 {
892     GraphicsLayer* contentsLayer = WebGraphicsLayer::layerByID(layerID);
893     if (!contentsLayer)
894         return;
895
896     toWebGraphicsLayer(contentsLayer)->setVisibleRect(visibleRect);
897     if (trajectoryVector != FloatPoint::zero()) {
898         m_webPage->scrollOverflowWithTrajectoryVector(trajectoryVector);
899         toWebGraphicsLayer(contentsLayer)->setVisibleContentRectTrajectoryVector(trajectoryVector);
900
901 #if ENABLE(TIZEN_CSS_OVERFLOW_SCROLL_SCROLLBAR)
902         const Vector<GraphicsLayer*>& childLayers = contentsLayer->children();
903         for (int i = 0; i < childLayers.size(); ++i)
904             if (childLayers[i]->isScrollbar())
905                toWebGraphicsLayer(childLayers[i])->startAnimation();
906 #endif
907     }
908     else
909         toWebGraphicsLayer(contentsLayer)->adjustVisibleRect();
910
911     scheduleLayerFlush();
912 }
913 #endif
914
915 #if ENABLE(TIZEN_CSS_OVERFLOW_SCROLL_ACCELERATION)
916 void LayerTreeCoordinator::addOrUpdateScrollingLayer(WebCore::GraphicsLayer* scrollingLayer, WebCore::GraphicsLayer* contentsLayer, const WebCore::IntSize& scrollSize)
917 {
918     if (!scrollingLayer || !contentsLayer)
919         return;
920
921     toWebGraphicsLayer(contentsLayer)->setIsOverflow(true);
922 #if !ENABLE(TIZEN_CSS_OVERFLOW_SCROLL_ACCELERATION_ON_UI_SIDE)
923     // FIXME: We might need to consider paddingBox margin for overflow scroll layer
924     // FloatPoint offset(-scrollingLayer->offsetFromRenderer().width() - scrollingLayer->boundsOrigin().x()
925     //        , -scrollingLayer->offsetFromRenderer().height() - scrollingLayer->boundsOrigin().y());
926     FloatPoint offset(scrollingLayer->boundsOrigin());
927     contentsLayer->setPosition(-offset);
928
929     IntRect visibleRect(FloatRect(offset, scrollingLayer->size()));
930     toWebGraphicsLayer(contentsLayer)->setVisibleRect(visibleRect);
931
932     // FIXME: Need to set trajectoryVector?
933     // FloatPoint trajectoryVector(scrollingLayer->trajectoryVector());
934     // if (trajectoryVector != FloatPoint::zero())
935         //toWebGraphicsLayer(contentsLayer)->setVisibleContentRectTrajectoryVector(-trajectoryVector);
936
937     // FIXME: Scale factor might be changed.
938     // toWebGraphicsLayer(contentsLayer)->setContentsScale(m_contentsScale);
939 #else
940     setNeedsOneShotDrawingSynchronization();
941 #endif
942     toWebGraphicsLayer(contentsLayer)->adjustVisibleRect();
943 }
944
945 void LayerTreeCoordinator::removeScrollingLayer(WebCore::GraphicsLayer* scrollingLayer, WebCore::GraphicsLayer* contentsLayer)
946 {
947     if (!scrollingLayer || !contentsLayer)
948         return;
949
950     toWebGraphicsLayer(contentsLayer)->setIsOverflow(false);
951     toWebGraphicsLayer(contentsLayer)->syncLayerState();
952 }
953 #endif // ENABLE(TIZEN_CSS_OVERFLOW_SCROLL_ACCELERATION)
954
955 #if ENABLE(TIZEN_ONESHOT_DRAWING_SYNCHRONIZATION)
956 void LayerTreeCoordinator::setNeedsOneShotDrawingSynchronization()
957 {
958     m_needsOneShotDrawingSynchronization = true;
959 }
960 #endif
961
962 #if ENABLE(TIZEN_LAYER_FLUSH_THROTTLING)
963 void LayerTreeCoordinator::setDeferLayerFlush(bool deferLayerFlushEnabled)
964 {
965     m_deferLayerFlushEnabled = deferLayerFlushEnabled;
966     m_layerFlushTimerDelayLevel = 0;
967     double newDelay = deferredLayerFlushDelay();
968
969     // If the m_layerFlushTimer is already activated, we stop the old timer and then begin the timer with a new delay
970     if (m_layerFlushTimerDelay != newDelay && m_layerFlushTimer.isActive()) {
971         m_layerFlushTimer.stop();
972         m_layerFlushTimer.startOneShot(newDelay);
973     }
974     m_layerFlushTimerDelay = newDelay;
975
976 #if ENABLE(TIZEN_SYNC_REQUEST_ANIMATION_FRAME)
977     if (m_layerFlushTimerDelay == 0.0)
978         m_webPage->resumeAnimationController();
979 #endif
980 }
981
982 float LayerTreeCoordinator::deferredLayerFlushDelay()
983 {
984     if (!m_deferLayerFlushEnabled)
985          return 0;
986
987     if (m_layerFlushTimerDelayLevel >= s_layerFlushTimerDelayMaxLevel)
988         m_layerFlushTimerDelayLevel = s_layerFlushTimerDelayMaxLevel - 1;
989
990     return s_layerFlushTimerDelayTable[m_layerFlushTimerDelayLevel++];
991 }
992 #endif
993
994 #if ENABLE(TIZEN_CUTOFF_TILES_OVER_MEMORY_LIMIT)
995 static bool AscendingTileSortByDistance(TileCutOffInfo first, TileCutOffInfo second)
996 {
997     if (first.m_distance < second.m_distance)
998         return true;
999
1000     return false;
1001 }
1002
1003 void LayerTreeCoordinator::calculateCutOffThreshold()
1004 {
1005     Vector<WebCore::TileCutOffInfo> tilesCutOffInfo;
1006     HashSet<WebCore::WebGraphicsLayer*>::iterator end = m_registeredLayers.end();
1007     for (HashSet<WebCore::WebGraphicsLayer*>::iterator it = m_registeredLayers.begin(); it != end; ++it)
1008         tilesCutOffInfo.append((*it)->getCutOffInfoList());
1009     tilesCutOffInfo.append(toWebGraphicsLayer(m_nonCompositedContentLayer.get())->getCutOffInfoList());
1010
1011     std::sort(tilesCutOffInfo.begin(), tilesCutOffInfo.end(), AscendingTileSortByDistance);
1012
1013     size_t allocatedMemory = 0;
1014     // FIXME: This patch will be considered in future.
1015     // Need to correct offscreen-to-onscreen animation layer's tile cutoff computation
1016     const size_t memoryLimit = 30 * 1024 * 1024; // 30 MB
1017     double cutOffDistance = std::numeric_limits<double>::max();
1018     for (size_t i = 0; i < tilesCutOffInfo.size(); ++i) {
1019         TileCutOffInfo cutOffInfo = tilesCutOffInfo[i];
1020         allocatedMemory += cutOffInfo.m_allocatedMemoryByte;
1021         if (memoryLimit < allocatedMemory) {
1022             cutOffDistance = cutOffInfo.m_distance;
1023             break;
1024         }
1025     }
1026
1027     for (HashSet<WebCore::WebGraphicsLayer*>::iterator it = m_registeredLayers.begin(); it != end; ++it)
1028         (*it)->setCutOffDistance(cutOffDistance);
1029
1030     toWebGraphicsLayer(m_nonCompositedContentLayer.get())->setCutOffDistance(cutOffDistance);
1031 }
1032 #endif
1033
1034 const double ReleaseInactiveAtlasesTimerInterval = 0.5;
1035
1036 void LayerTreeCoordinator::scheduleReleaseInactiveAtlases()
1037 {
1038     if (!m_releaseInactiveAtlasesTimer.isActive())
1039         m_releaseInactiveAtlasesTimer.startRepeating(ReleaseInactiveAtlasesTimerInterval);
1040 }
1041
1042 void LayerTreeCoordinator::releaseInactiveAtlasesTimerFired(Timer<LayerTreeCoordinator>*)
1043 {
1044     // We always want to keep one atlas for non-composited content.
1045     OwnPtr<UpdateAtlas> atlasToKeepAnyway;
1046     bool foundActiveAtlasForNonCompositedContent = false;
1047     for (int i = m_updateAtlases.size() - 1;  i >= 0; --i) {
1048         UpdateAtlas* atlas = m_updateAtlases[i].get();
1049         if (!atlas->isInUse())
1050             atlas->addTimeInactive(ReleaseInactiveAtlasesTimerInterval);
1051         bool usableForNonCompositedContent = !atlas->supportsAlpha();
1052         if (atlas->isInactive()) {
1053             if (!foundActiveAtlasForNonCompositedContent && !atlasToKeepAnyway && usableForNonCompositedContent)
1054                 atlasToKeepAnyway = m_updateAtlases[i].release();
1055             m_updateAtlases.remove(i);
1056         } else if (usableForNonCompositedContent)
1057             foundActiveAtlasForNonCompositedContent = true;
1058     }
1059
1060     if (!foundActiveAtlasForNonCompositedContent && atlasToKeepAnyway)
1061         m_updateAtlases.append(atlasToKeepAnyway.release());
1062
1063     if (m_updateAtlases.size() <= 1)
1064         m_releaseInactiveAtlasesTimer.stop();
1065 }
1066
1067 } // namespace WebKit