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. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#import "config.h" 27#import "LayerTreeHostMac.h" 28 29#import "DrawingAreaImpl.h" 30#import "LayerHostingContext.h" 31#import "WebPage.h" 32#import "WebProcess.h" 33#import <QuartzCore/CATransaction.h> 34#import <WebCore/Frame.h> 35#import <WebCore/FrameView.h> 36#import <WebCore/GraphicsLayerCA.h> 37#import <WebCore/PlatformCALayer.h> 38#import <WebCore/Settings.h> 39 40using namespace WebCore; 41 42@interface CATransaction (Details) 43+ (void)synchronize; 44@end 45 46namespace WebKit { 47 48PassRefPtr<LayerTreeHostMac> LayerTreeHostMac::create(WebPage* webPage) 49{ 50 RefPtr<LayerTreeHostMac> host = adoptRef(new LayerTreeHostMac(webPage)); 51 host->initialize(); 52 return host.release(); 53} 54 55LayerTreeHostMac::LayerTreeHostMac(WebPage* webPage) 56 : LayerTreeHost(webPage) 57 , m_isValid(true) 58 , m_notifyAfterScheduledLayerFlush(false) 59 , m_layerFlushScheduler(this) 60{ 61} 62 63LayerTreeHostMac::~LayerTreeHostMac() 64{ 65 ASSERT(!m_isValid); 66 ASSERT(!m_rootLayer); 67 ASSERT(!m_layerHostingContext); 68} 69 70const LayerTreeContext& LayerTreeHostMac::layerTreeContext() 71{ 72 return m_layerTreeContext; 73} 74 75void LayerTreeHostMac::scheduleLayerFlush() 76{ 77 m_layerFlushScheduler.schedule(); 78} 79 80void LayerTreeHostMac::setLayerFlushSchedulingEnabled(bool layerFlushingEnabled) 81{ 82 if (layerFlushingEnabled) 83 m_layerFlushScheduler.resume(); 84 else 85 m_layerFlushScheduler.suspend(); 86} 87 88void LayerTreeHostMac::setShouldNotifyAfterNextScheduledLayerFlush(bool notifyAfterScheduledLayerFlush) 89{ 90 m_notifyAfterScheduledLayerFlush = notifyAfterScheduledLayerFlush; 91} 92 93void LayerTreeHostMac::setRootCompositingLayer(GraphicsLayer* graphicsLayer) 94{ 95 m_nonCompositedContentLayer->removeAllChildren(); 96 97 // Add the accelerated layer tree hierarchy. 98 if (graphicsLayer) 99 m_nonCompositedContentLayer->addChild(graphicsLayer); 100} 101 102void LayerTreeHostMac::invalidate() 103{ 104 ASSERT(m_isValid); 105 106 m_isValid = false; 107 108 m_rootLayer = nullptr; 109 110 m_layerHostingContext->invalidate(); 111 m_layerHostingContext = nullptr; 112 m_layerFlushScheduler.invalidate(); 113} 114 115void LayerTreeHostMac::setNonCompositedContentsNeedDisplay() 116{ 117 m_nonCompositedContentLayer->setNeedsDisplay(); 118 119 PageOverlayLayerMap::iterator end = m_pageOverlayLayers.end(); 120 for (PageOverlayLayerMap::iterator it = m_pageOverlayLayers.begin(); it != end; ++it) 121 it->value->setNeedsDisplay(); 122 123 scheduleLayerFlush(); 124} 125 126void LayerTreeHostMac::setNonCompositedContentsNeedDisplayInRect(const IntRect& rect) 127{ 128 m_nonCompositedContentLayer->setNeedsDisplayInRect(rect); 129 130 PageOverlayLayerMap::iterator end = m_pageOverlayLayers.end(); 131 for (PageOverlayLayerMap::iterator it = m_pageOverlayLayers.begin(); it != end; ++it) 132 it->value->setNeedsDisplayInRect(rect); 133 134 scheduleLayerFlush(); 135} 136 137void LayerTreeHostMac::scrollNonCompositedContents(const IntRect& scrollRect) 138{ 139 setNonCompositedContentsNeedDisplayInRect(scrollRect); 140} 141 142void LayerTreeHostMac::forceRepaint() 143{ 144 scheduleLayerFlush(); 145 flushPendingLayerChanges(); 146 147 [CATransaction flush]; 148 [CATransaction synchronize]; 149} 150 151void LayerTreeHostMac::sizeDidChange(const IntSize& newSize) 152{ 153 m_rootLayer->setSize(newSize); 154 155 // If the newSize exposes new areas of the non-composited content a setNeedsDisplay is needed 156 // for those newly exposed areas. 157 FloatSize oldSize = m_nonCompositedContentLayer->size(); 158 m_nonCompositedContentLayer->setSize(newSize); 159 160 if (newSize.width() > oldSize.width()) { 161 float height = std::min(static_cast<float>(newSize.height()), oldSize.height()); 162 m_nonCompositedContentLayer->setNeedsDisplayInRect(FloatRect(oldSize.width(), 0, newSize.width() - oldSize.width(), height)); 163 } 164 165 if (newSize.height() > oldSize.height()) 166 m_nonCompositedContentLayer->setNeedsDisplayInRect(FloatRect(0, oldSize.height(), newSize.width(), newSize.height() - oldSize.height())); 167 168 PageOverlayLayerMap::iterator end = m_pageOverlayLayers.end(); 169 for (PageOverlayLayerMap::iterator it = m_pageOverlayLayers.begin(); it != end; ++it) 170 it->value->setSize(newSize); 171 172 scheduleLayerFlush(); 173 flushPendingLayerChanges(); 174 175 [CATransaction flush]; 176 [CATransaction synchronize]; 177} 178 179void LayerTreeHostMac::deviceOrPageScaleFactorChanged() 180{ 181 // Other layers learn of the scale factor change via WebPage::setDeviceScaleFactor. 182 m_nonCompositedContentLayer->deviceOrPageScaleFactorChanged(); 183} 184 185void LayerTreeHostMac::pageBackgroundTransparencyChanged() 186{ 187 m_nonCompositedContentLayer->setContentsOpaque(m_webPage->drawsBackground() && !m_webPage->drawsTransparentBackground()); 188} 189 190void LayerTreeHostMac::didInstallPageOverlay(PageOverlay* pageOverlay) 191{ 192 createPageOverlayLayer(pageOverlay); 193 scheduleLayerFlush(); 194} 195 196void LayerTreeHostMac::didUninstallPageOverlay(PageOverlay* pageOverlay) 197{ 198 destroyPageOverlayLayer(pageOverlay); 199 scheduleLayerFlush(); 200} 201 202void LayerTreeHostMac::setPageOverlayNeedsDisplay(PageOverlay* pageOverlay, const IntRect& rect) 203{ 204 GraphicsLayer* layer = m_pageOverlayLayers.get(pageOverlay); 205 206 if (!layer) 207 return; 208 209 layer->setNeedsDisplayInRect(rect); 210 scheduleLayerFlush(); 211} 212 213void LayerTreeHostMac::pauseRendering() 214{ 215 CALayer* root = m_rootLayer->platformLayer(); 216 [root setValue:(id)kCFBooleanTrue forKey:@"NSCAViewRenderPaused"]; 217 [[NSNotificationCenter defaultCenter] postNotificationName:@"NSCAViewRenderDidPauseNotification" object:nil userInfo:[NSDictionary dictionaryWithObject:root forKey:@"layer"]]; 218} 219 220void LayerTreeHostMac::resumeRendering() 221{ 222 CALayer* root = m_rootLayer->platformLayer(); 223 [root setValue:(id)kCFBooleanFalse forKey:@"NSCAViewRenderPaused"]; 224 [[NSNotificationCenter defaultCenter] postNotificationName:@"NSCAViewRenderDidResumeNotification" object:nil userInfo:[NSDictionary dictionaryWithObject:root forKey:@"layer"]]; 225} 226 227void LayerTreeHostMac::setLayerHostingMode(LayerHostingMode layerHostingMode) 228{ 229 if (layerHostingMode == m_layerHostingContext->layerHostingMode()) 230 return; 231 232 // The mode has changed. 233 234 // First, invalidate the old hosting context. 235 m_layerHostingContext->invalidate(); 236 m_layerHostingContext = nullptr; 237 238 // Create a new context and set it up. 239 switch (layerHostingMode) { 240 case LayerHostingModeDefault: 241 m_layerHostingContext = LayerHostingContext::createForPort(WebProcess::shared().compositingRenderServerPort()); 242 break; 243#if HAVE(LAYER_HOSTING_IN_WINDOW_SERVER) 244 case LayerHostingModeInWindowServer: 245 m_layerHostingContext = LayerHostingContext::createForWindowServer(); 246 break; 247#endif 248 } 249 250 m_layerHostingContext->setRootLayer(m_rootLayer->platformLayer()); 251 m_layerTreeContext.contextID = m_layerHostingContext->contextID(); 252 253 scheduleLayerFlush(); 254} 255 256void LayerTreeHostMac::notifyAnimationStarted(const WebCore::GraphicsLayer*, double time) 257{ 258} 259 260void LayerTreeHostMac::notifyFlushRequired(const WebCore::GraphicsLayer*) 261{ 262} 263 264void LayerTreeHostMac::paintContents(const GraphicsLayer* graphicsLayer, GraphicsContext& graphicsContext, GraphicsLayerPaintingPhase, const IntRect& clipRect) 265{ 266 if (graphicsLayer == m_nonCompositedContentLayer) { 267 m_webPage->drawRect(graphicsContext, clipRect); 268 return; 269 } 270 271 PageOverlayLayerMap::iterator end = m_pageOverlayLayers.end(); 272 for (PageOverlayLayerMap::iterator it = m_pageOverlayLayers.begin(); it != end; ++it) { 273 if (it->value == graphicsLayer) { 274 m_webPage->drawPageOverlay(it->key, graphicsContext, clipRect); 275 break; 276 } 277 } 278} 279 280float LayerTreeHostMac::deviceScaleFactor() const 281{ 282 return m_webPage->corePage()->deviceScaleFactor(); 283} 284 285bool LayerTreeHostMac::flushLayers() 286{ 287 performScheduledLayerFlush(); 288 return true; 289} 290 291void LayerTreeHostMac::initialize() 292{ 293 // Create a root layer. 294 m_rootLayer = GraphicsLayer::create(graphicsLayerFactory(), this); 295#ifndef NDEBUG 296 m_rootLayer->setName("LayerTreeHost root layer"); 297#endif 298 m_rootLayer->setDrawsContent(false); 299 m_rootLayer->setSize(m_webPage->size()); 300 static_cast<GraphicsLayerCA*>(m_rootLayer.get())->platformCALayer()->setGeometryFlipped(true); 301 302 m_nonCompositedContentLayer = GraphicsLayer::create(graphicsLayerFactory(), this); 303 static_cast<GraphicsLayerCA*>(m_nonCompositedContentLayer.get())->setAllowTiledLayer(false); 304#ifndef NDEBUG 305 m_nonCompositedContentLayer->setName("LayerTreeHost non-composited content"); 306#endif 307 m_nonCompositedContentLayer->setDrawsContent(true); 308 m_nonCompositedContentLayer->setContentsOpaque(m_webPage->drawsBackground() && !m_webPage->drawsTransparentBackground()); 309 m_nonCompositedContentLayer->setSize(m_webPage->size()); 310 if (m_webPage->corePage()->settings()->acceleratedDrawingEnabled()) 311 m_nonCompositedContentLayer->setAcceleratesDrawing(true); 312 313 m_rootLayer->addChild(m_nonCompositedContentLayer.get()); 314 315 if (m_webPage->hasPageOverlay()) { 316 PageOverlayList& pageOverlays = m_webPage->pageOverlays(); 317 PageOverlayList::iterator end = pageOverlays.end(); 318 for (PageOverlayList::iterator it = pageOverlays.begin(); it != end; ++it) 319 createPageOverlayLayer(it->get()); 320 } 321 322 switch (m_webPage->layerHostingMode()) { 323 case LayerHostingModeDefault: 324 m_layerHostingContext = LayerHostingContext::createForPort(WebProcess::shared().compositingRenderServerPort()); 325 break; 326#if HAVE(LAYER_HOSTING_IN_WINDOW_SERVER) 327 case LayerHostingModeInWindowServer: 328 m_layerHostingContext = LayerHostingContext::createForWindowServer(); 329 break; 330#endif 331 } 332 333 m_layerHostingContext->setRootLayer(m_rootLayer->platformLayer()); 334 m_layerTreeContext.contextID = m_layerHostingContext->contextID(); 335 336 setLayerFlushSchedulingEnabled(!m_webPage->drawingArea() || !m_webPage->drawingArea()->layerTreeStateIsFrozen()); 337 scheduleLayerFlush(); 338} 339 340void LayerTreeHostMac::performScheduledLayerFlush() 341{ 342 { 343 RefPtr<LayerTreeHostMac> protect(this); 344 m_webPage->layoutIfNeeded(); 345 346 if (!m_isValid) 347 return; 348 } 349 350 if (!flushPendingLayerChanges()) 351 return; 352 353 if (m_notifyAfterScheduledLayerFlush) { 354 // Let the drawing area know that we've done a flush of the layer changes. 355 static_cast<DrawingAreaImpl*>(m_webPage->drawingArea())->layerHostDidFlushLayers(); 356 m_notifyAfterScheduledLayerFlush = false; 357 } 358} 359 360bool LayerTreeHostMac::flushPendingLayerChanges() 361{ 362 if (m_layerFlushScheduler.isSuspended()) 363 return false; 364 365 m_rootLayer->flushCompositingStateForThisLayerOnly(); 366 m_nonCompositedContentLayer->flushCompositingStateForThisLayerOnly(); 367 368 PageOverlayLayerMap::iterator end = m_pageOverlayLayers.end(); 369 for (PageOverlayLayerMap::iterator it = m_pageOverlayLayers.begin(); it != end; ++it) 370 it->value->flushCompositingStateForThisLayerOnly(); 371 372 return m_webPage->corePage()->mainFrame()->view()->flushCompositingStateIncludingSubframes(); 373} 374 375void LayerTreeHostMac::createPageOverlayLayer(PageOverlay* pageOverlay) 376{ 377 OwnPtr<GraphicsLayer> layer = GraphicsLayer::create(graphicsLayerFactory(), this); 378#ifndef NDEBUG 379 layer->setName("LayerTreeHost page overlay content"); 380#endif 381 382 layer->setAcceleratesDrawing(m_webPage->corePage()->settings()->acceleratedDrawingEnabled()); 383 layer->setDrawsContent(true); 384 layer->setSize(m_webPage->size()); 385 layer->setShowDebugBorder(m_webPage->corePage()->settings()->showDebugBorders()); 386 layer->setShowRepaintCounter(m_webPage->corePage()->settings()->showRepaintCounter()); 387 388 m_rootLayer->addChild(layer.get()); 389 390 m_pageOverlayLayers.add(pageOverlay, layer.release()); 391} 392 393void LayerTreeHostMac::destroyPageOverlayLayer(PageOverlay* pageOverlay) 394{ 395 OwnPtr<GraphicsLayer> layer = m_pageOverlayLayers.take(pageOverlay); 396 ASSERT(layer); 397 398 layer->removeFromParent(); 399} 400 401} // namespace WebKit 402