2 * Copyright (C) 2011 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #import "TiledCoreAnimationDrawingArea.h"
31 #import "ColorSpaceData.h"
32 #import "DrawingAreaProxyMessages.h"
33 #import "LayerHostingContext.h"
34 #import "LayerTreeContext.h"
35 #import "ViewGestureControllerMessages.h"
38 #import "WebPageCreationParameters.h"
39 #import "WebPageProxyMessages.h"
40 #import "WebProcess.h"
41 #import <QuartzCore/QuartzCore.h>
42 #import <WebCore/FrameView.h>
43 #import <WebCore/GraphicsContext.h>
44 #import <WebCore/GraphicsLayerCA.h>
45 #import <WebCore/MainFrame.h>
46 #import <WebCore/Page.h>
47 #import <WebCore/PlatformCAAnimationMac.h>
48 #import <WebCore/RenderLayerBacking.h>
49 #import <WebCore/RenderLayerCompositor.h>
50 #import <WebCore/RenderView.h>
51 #import <WebCore/ScrollbarTheme.h>
52 #import <WebCore/Settings.h>
53 #import <WebCore/TiledBacking.h>
54 #import <wtf/MainThread.h>
56 #if ENABLE(ASYNC_SCROLLING)
57 #import <WebCore/AsyncScrollingCoordinator.h>
58 #import <WebCore/ScrollingThread.h>
59 #import <WebCore/ScrollingTree.h>
62 @interface CATransaction (Details)
66 using namespace WebCore;
70 TiledCoreAnimationDrawingArea::TiledCoreAnimationDrawingArea(WebPage& webPage, const WebPageCreationParameters& parameters)
71 : DrawingArea(DrawingAreaTypeTiledCoreAnimation, webPage)
72 , m_layerTreeStateIsFrozen(false)
73 , m_layerFlushScheduler(this)
74 , m_isPaintingSuspended(!(parameters.viewState & ViewState::IsVisible))
75 , m_exposedRect(FloatRect::infiniteRect())
76 , m_scrolledExposedRect(FloatRect::infiniteRect())
77 , m_transientZoomScale(1)
78 , m_sendDidUpdateViewStateTimer(RunLoop::main(), this, &TiledCoreAnimationDrawingArea::didUpdateViewStateTimerFired)
80 m_webPage.corePage()->settings().setForceCompositingMode(true);
82 m_hostingLayer = [CALayer layer];
83 [m_hostingLayer setFrame:m_webPage.bounds()];
84 [m_hostingLayer setOpaque:YES];
85 [m_hostingLayer setGeometryFlipped:YES];
87 updateLayerHostingContext();
88 setColorSpace(parameters.colorSpace);
90 LayerTreeContext layerTreeContext;
91 layerTreeContext.contextID = m_layerHostingContext->contextID();
92 m_webPage.send(Messages::DrawingAreaProxy::EnterAcceleratedCompositingMode(0, layerTreeContext));
95 TiledCoreAnimationDrawingArea::~TiledCoreAnimationDrawingArea()
97 m_layerFlushScheduler.invalidate();
100 void TiledCoreAnimationDrawingArea::setNeedsDisplay()
104 void TiledCoreAnimationDrawingArea::setNeedsDisplayInRect(const IntRect& rect)
108 void TiledCoreAnimationDrawingArea::scroll(const IntRect& scrollRect, const IntSize& scrollDelta)
110 updateScrolledExposedRect();
113 void TiledCoreAnimationDrawingArea::setRootCompositingLayer(GraphicsLayer* graphicsLayer)
115 CALayer *rootLayer = graphicsLayer ? graphicsLayer->platformLayer() : nil;
117 if (m_layerTreeStateIsFrozen) {
118 m_pendingRootLayer = rootLayer;
122 setRootCompositingLayer(rootLayer);
125 void TiledCoreAnimationDrawingArea::forceRepaint()
127 if (m_layerTreeStateIsFrozen)
130 for (Frame* frame = &m_webPage.corePage()->mainFrame(); frame; frame = frame->tree().traverseNext()) {
131 FrameView* frameView = frame->view();
132 if (!frameView || !frameView->tiledBacking())
135 frameView->tiledBacking()->forceRepaint();
139 [CATransaction flush];
140 [CATransaction synchronize];
143 bool TiledCoreAnimationDrawingArea::forceRepaintAsync(uint64_t callbackID)
145 if (m_layerTreeStateIsFrozen)
148 dispatchAfterEnsuringUpdatedScrollPosition([this, callbackID] {
149 m_webPage.drawingArea()->forceRepaint();
150 m_webPage.send(Messages::WebPageProxy::VoidCallback(callbackID));
155 void TiledCoreAnimationDrawingArea::setLayerTreeStateIsFrozen(bool layerTreeStateIsFrozen)
157 if (m_layerTreeStateIsFrozen == layerTreeStateIsFrozen)
160 m_layerTreeStateIsFrozen = layerTreeStateIsFrozen;
161 if (m_layerTreeStateIsFrozen)
162 m_layerFlushScheduler.suspend();
164 m_layerFlushScheduler.resume();
167 bool TiledCoreAnimationDrawingArea::layerTreeStateIsFrozen() const
169 return m_layerTreeStateIsFrozen;
172 void TiledCoreAnimationDrawingArea::scheduleCompositingLayerFlush()
174 m_layerFlushScheduler.schedule();
177 void TiledCoreAnimationDrawingArea::scheduleCompositingLayerFlushImmediately()
179 scheduleCompositingLayerFlush();
182 void TiledCoreAnimationDrawingArea::updatePreferences(const WebPreferencesStore&)
184 Settings& settings = m_webPage.corePage()->settings();
186 #if ENABLE(ASYNC_SCROLLING)
187 if (AsyncScrollingCoordinator* scrollingCoordinator = toAsyncScrollingCoordinator(m_webPage.corePage()->scrollingCoordinator())) {
188 bool scrollingPerformanceLoggingEnabled = m_webPage.scrollingPerformanceLoggingEnabled();
189 ScrollingThread::dispatch(bind(&ScrollingTree::setScrollingPerformanceLoggingEnabled, scrollingCoordinator->scrollingTree(), scrollingPerformanceLoggingEnabled));
193 // Fixed position elements need to be composited and create stacking contexts
194 // in order to be scrolled by the ScrollingCoordinator. We also want to keep
195 // Settings:setFixedPositionCreatesStackingContext() enabled for iOS. See
196 // <rdar://problem/9813262> for more details.
197 settings.setAcceleratedCompositingForFixedPositionEnabled(true);
198 settings.setFixedPositionCreatesStackingContext(true);
200 bool showTiledScrollingIndicator = settings.showTiledScrollingIndicator();
201 if (showTiledScrollingIndicator == !!m_debugInfoLayer)
204 updateDebugInfoLayer(showTiledScrollingIndicator);
207 void TiledCoreAnimationDrawingArea::mainFrameContentSizeChanged(const IntSize& size)
209 m_webPage.pageOverlayController().didChangeDocumentSize();
212 void TiledCoreAnimationDrawingArea::updateIntrinsicContentSizeIfNeeded()
214 if (!m_webPage.minimumLayoutSize().width())
217 FrameView* frameView = m_webPage.mainFrameView();
221 if (frameView->needsLayout())
224 IntSize contentSize = frameView->autoSizingIntrinsicContentSize();
225 if (m_lastSentIntrinsicContentSize == contentSize)
228 m_lastSentIntrinsicContentSize = contentSize;
229 m_webPage.send(Messages::DrawingAreaProxy::IntrinsicContentSizeDidChange(contentSize));
232 void TiledCoreAnimationDrawingArea::dispatchAfterEnsuringUpdatedScrollPosition(std::function<void ()> function)
234 #if ENABLE(ASYNC_SCROLLING)
235 if (!m_webPage.corePage()->scrollingCoordinator()) {
241 m_webPage.corePage()->scrollingCoordinator()->commitTreeStateIfNeeded();
243 if (!m_layerTreeStateIsFrozen)
244 m_layerFlushScheduler.suspend();
246 // It is possible for the drawing area to be destroyed before the bound block
247 // is invoked, so grab a reference to the web page here so we can access the drawing area through it.
248 // (The web page is already kept alive by dispatchAfterEnsuringUpdatedScrollPosition).
249 WebPage* webPage = &m_webPage;
251 ScrollingThread::dispatchBarrier([this, webPage, function] {
252 DrawingArea* drawingArea = webPage->drawingArea();
258 if (!m_layerTreeStateIsFrozen)
259 m_layerFlushScheduler.resume();
268 bool TiledCoreAnimationDrawingArea::flushLayers()
270 ASSERT(!m_layerTreeStateIsFrozen);
272 // This gets called outside of the normal event loop so wrap in an autorelease pool
273 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
275 m_webPage.layoutIfNeeded();
277 updateIntrinsicContentSizeIfNeeded();
279 if (m_pendingRootLayer) {
280 setRootCompositingLayer(m_pendingRootLayer.get());
281 m_pendingRootLayer = nullptr;
284 FloatRect visibleRect = [m_hostingLayer frame];
285 visibleRect.intersect(m_scrolledExposedRect);
286 m_webPage.pageOverlayController().flushPageOverlayLayers(visibleRect);
288 bool returnValue = m_webPage.mainFrameView()->flushCompositingStateIncludingSubframes();
289 #if ENABLE(ASYNC_SCROLLING)
290 if (ScrollingCoordinator* scrollingCoordinator = m_webPage.corePage()->scrollingCoordinator())
291 scrollingCoordinator->commitTreeStateIfNeeded();
294 // If we have an active transient zoom, we want the zoom to win over any changes
295 // that WebCore makes to the relevant layers, so re-apply our changes after flushing.
296 if (m_transientZoomScale != 1)
297 applyTransientZoomToLayers(m_transientZoomScale, m_transientZoomOrigin);
303 void TiledCoreAnimationDrawingArea::viewStateDidChange(ViewState::Flags changed, bool wantsDidUpdateViewState)
305 if (changed & ViewState::IsVisible) {
306 if (m_webPage.isVisible())
312 if (wantsDidUpdateViewState)
313 m_sendDidUpdateViewStateTimer.startOneShot(0);
316 void TiledCoreAnimationDrawingArea::didUpdateViewStateTimerFired()
318 [CATransaction flush];
319 m_webPage.send(Messages::WebPageProxy::DidUpdateViewState());
322 void TiledCoreAnimationDrawingArea::suspendPainting()
324 ASSERT(!m_isPaintingSuspended);
325 m_isPaintingSuspended = true;
327 [m_hostingLayer setValue:@YES forKey:@"NSCAViewRenderPaused"];
328 [[NSNotificationCenter defaultCenter] postNotificationName:@"NSCAViewRenderDidPauseNotification" object:nil userInfo:[NSDictionary dictionaryWithObject:m_hostingLayer.get() forKey:@"layer"]];
331 void TiledCoreAnimationDrawingArea::resumePainting()
333 if (!m_isPaintingSuspended) {
334 // FIXME: We can get a call to resumePainting when painting is not suspended.
335 // This happens when sending a synchronous message to create a new page. See <rdar://problem/8976531>.
338 m_isPaintingSuspended = false;
340 [m_hostingLayer setValue:@NO forKey:@"NSCAViewRenderPaused"];
341 [[NSNotificationCenter defaultCenter] postNotificationName:@"NSCAViewRenderDidResumeNotification" object:nil userInfo:[NSDictionary dictionaryWithObject:m_hostingLayer.get() forKey:@"layer"]];
344 void TiledCoreAnimationDrawingArea::setExposedRect(const FloatRect& exposedRect)
346 m_exposedRect = exposedRect;
347 updateScrolledExposedRect();
350 void TiledCoreAnimationDrawingArea::updateScrolledExposedRect()
352 FrameView* frameView = m_webPage.mainFrameView();
356 m_scrolledExposedRect = m_exposedRect;
359 if (!m_exposedRect.isInfinite()) {
360 IntPoint scrollPositionWithOrigin = frameView->scrollPosition() + toIntSize(frameView->scrollOrigin());
361 m_scrolledExposedRect.moveBy(scrollPositionWithOrigin);
365 frameView->setExposedRect(m_scrolledExposedRect);
367 m_webPage.pageOverlayController().didChangeExposedRect();
370 void TiledCoreAnimationDrawingArea::updateGeometry(const IntSize& viewSize, const IntSize& layerPosition)
372 m_inUpdateGeometry = true;
374 IntSize size = viewSize;
375 IntSize contentSize = IntSize(-1, -1);
377 if (!m_webPage.minimumLayoutSize().width() || m_webPage.autoSizingShouldExpandToViewHeight())
378 m_webPage.setSize(size);
380 FrameView* frameView = m_webPage.mainFrameView();
382 if (m_webPage.autoSizingShouldExpandToViewHeight() && frameView)
383 frameView->setAutoSizeFixedMinimumHeight(viewSize.height());
385 m_webPage.layoutIfNeeded();
387 if (m_webPage.minimumLayoutSize().width() && frameView) {
388 contentSize = frameView->autoSizingIntrinsicContentSize();
392 if (!m_layerTreeStateIsFrozen)
395 [CATransaction begin];
396 [CATransaction setDisableActions:YES];
398 [m_hostingLayer setFrame:CGRectMake(layerPosition.width(), layerPosition.height(), viewSize.width(), viewSize.height())];
400 [CATransaction commit];
402 [CATransaction flush];
403 [CATransaction synchronize];
405 m_webPage.send(Messages::DrawingAreaProxy::DidUpdateGeometry());
407 m_inUpdateGeometry = false;
410 void TiledCoreAnimationDrawingArea::setDeviceScaleFactor(float deviceScaleFactor)
412 m_webPage.setDeviceScaleFactor(deviceScaleFactor);
415 void TiledCoreAnimationDrawingArea::setLayerHostingMode(LayerHostingMode)
417 updateLayerHostingContext();
419 // Finally, inform the UIProcess that the context has changed.
420 LayerTreeContext layerTreeContext;
421 layerTreeContext.contextID = m_layerHostingContext->contextID();
422 m_webPage.send(Messages::DrawingAreaProxy::UpdateAcceleratedCompositingMode(0, layerTreeContext));
425 void TiledCoreAnimationDrawingArea::setColorSpace(const ColorSpaceData& colorSpace)
427 m_layerHostingContext->setColorSpace(colorSpace.cgColorSpace.get());
430 void TiledCoreAnimationDrawingArea::updateLayerHostingContext()
432 RetainPtr<CGColorSpaceRef> colorSpace;
434 // Invalidate the old context.
435 if (m_layerHostingContext) {
436 colorSpace = m_layerHostingContext->colorSpace();
437 m_layerHostingContext->invalidate();
438 m_layerHostingContext = nullptr;
441 // Create a new context and set it up.
442 switch (m_webPage.layerHostingMode()) {
443 case LayerHostingMode::InProcess:
444 m_layerHostingContext = LayerHostingContext::createForPort(WebProcess::shared().compositingRenderServerPort());
446 #if HAVE(OUT_OF_PROCESS_LAYER_HOSTING)
447 case LayerHostingMode::OutOfProcess:
448 m_layerHostingContext = LayerHostingContext::createForExternalHostingProcess();
454 m_layerHostingContext->setRootLayer(m_hostingLayer.get());
457 m_layerHostingContext->setColorSpace(colorSpace.get());
460 void TiledCoreAnimationDrawingArea::setRootCompositingLayer(CALayer *layer)
462 ASSERT(!m_layerTreeStateIsFrozen);
464 [CATransaction begin];
465 [CATransaction setDisableActions:YES];
467 [m_hostingLayer setSublayers:layer ? @[ layer, m_webPage.pageOverlayController().viewOverlayRootLayer()->platformLayer() ] : @[ ]];
469 bool hadRootLayer = !!m_rootLayer;
471 [m_rootLayer setSublayerTransform:m_transform];
473 if (hadRootLayer != !!layer)
474 m_layerHostingContext->setRootLayer(layer ? m_hostingLayer.get() : 0);
476 updateDebugInfoLayer(m_webPage.corePage()->settings().showTiledScrollingIndicator());
478 [CATransaction commit];
481 TiledBacking* TiledCoreAnimationDrawingArea::mainFrameTiledBacking() const
483 FrameView* frameView = m_webPage.mainFrameView();
484 return frameView ? frameView->tiledBacking() : nullptr;
487 void TiledCoreAnimationDrawingArea::updateDebugInfoLayer(bool showLayer)
490 if (TiledBacking* tiledBacking = mainFrameTiledBacking()) {
491 if (PlatformCALayer* indicatorLayer = tiledBacking->tiledScrollingIndicatorLayer())
492 m_debugInfoLayer = indicatorLayer->platformLayer();
495 if (m_debugInfoLayer) {
497 [m_debugInfoLayer setName:@"Debug Info"];
499 [m_hostingLayer addSublayer:m_debugInfoLayer.get()];
501 } else if (m_debugInfoLayer) {
502 [m_debugInfoLayer removeFromSuperlayer];
503 m_debugInfoLayer = nullptr;
507 bool TiledCoreAnimationDrawingArea::shouldUseTiledBackingForFrameView(const FrameView* frameView)
509 return frameView && frameView->frame().isMainFrame();
512 PlatformCALayer* TiledCoreAnimationDrawingArea::layerForTransientZoom() const
514 RenderLayerBacking* renderViewBacking = m_webPage.mainFrameView()->renderView()->layer()->backing();
516 if (GraphicsLayer* contentsContainmentLayer = renderViewBacking->contentsContainmentLayer())
517 return toGraphicsLayerCA(contentsContainmentLayer)->platformCALayer();
519 return toGraphicsLayerCA(renderViewBacking->graphicsLayer())->platformCALayer();
522 PlatformCALayer* TiledCoreAnimationDrawingArea::shadowLayerForTransientZoom() const
524 RenderLayerCompositor& renderLayerCompositor = m_webPage.mainFrameView()->renderView()->compositor();
526 if (GraphicsLayer* shadowGraphicsLayer = renderLayerCompositor.layerForContentShadow())
527 return toGraphicsLayerCA(shadowGraphicsLayer)->platformCALayer();
532 static FloatPoint shadowLayerPositionForFrame(FrameView& frameView, FloatPoint origin)
534 FloatPoint position = frameView.renderView()->documentRect().location() + FloatPoint(0, FrameView::yPositionForRootContentLayer(frameView.scrollPosition(), frameView.topContentInset(), frameView.headerHeight()));
536 return position + origin.expandedTo(FloatPoint());
539 static FloatRect shadowLayerBoundsForFrame(FrameView& frameView, float transientScale)
541 FloatRect clipLayerFrame(frameView.renderView()->documentRect());
542 FloatRect shadowLayerFrame = clipLayerFrame;
544 shadowLayerFrame.scale(transientScale / frameView.frame().page()->pageScaleFactor());
545 shadowLayerFrame.intersect(clipLayerFrame);
547 return shadowLayerFrame;
550 void TiledCoreAnimationDrawingArea::applyTransientZoomToLayers(double scale, FloatPoint origin)
552 // FIXME: Scrollbars should stay in-place and change height while zooming.
557 TransformationMatrix transform;
558 transform.translate(origin.x(), origin.y());
559 transform.scale(scale);
561 PlatformCALayer* zoomLayer = layerForTransientZoom();
562 zoomLayer->setTransform(transform);
563 zoomLayer->setAnchorPoint(FloatPoint3D());
564 zoomLayer->setPosition(FloatPoint3D());
566 if (PlatformCALayer* shadowLayer = shadowLayerForTransientZoom()) {
567 FrameView& frameView = *m_webPage.mainFrameView();
568 shadowLayer->setBounds(shadowLayerBoundsForFrame(frameView, scale));
569 shadowLayer->setPosition(shadowLayerPositionForFrame(frameView, origin));
572 m_transientZoomScale = scale;
573 m_transientZoomOrigin = origin;
576 void TiledCoreAnimationDrawingArea::adjustTransientZoom(double scale, FloatPoint origin)
578 applyTransientZoomToLayers(scale, origin);
580 double currentPageScale = m_webPage.pageScaleFactor();
581 if (scale > currentPageScale)
584 FrameView* frameView = m_webPage.mainFrameView();
585 FloatRect tileCoverageRect = frameView->visibleContentRectIncludingScrollbars();
586 tileCoverageRect.moveBy(-origin);
587 tileCoverageRect.scale(currentPageScale / scale);
588 frameView->renderView()->layer()->backing()->tiledBacking()->prepopulateRect(tileCoverageRect);
591 static RetainPtr<CABasicAnimation> transientZoomSnapAnimationForKeyPath(String keyPath)
593 const float transientZoomSnapBackDuration = 0.25;
595 RetainPtr<CABasicAnimation> animation = [CABasicAnimation animationWithKeyPath:keyPath];
596 [animation setDuration:transientZoomSnapBackDuration];
597 [animation setFillMode:kCAFillModeForwards];
598 [animation setRemovedOnCompletion:false];
599 [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
604 void TiledCoreAnimationDrawingArea::commitTransientZoom(double scale, FloatPoint origin)
606 FrameView& frameView = *m_webPage.mainFrameView();
607 FloatRect visibleContentRect = frameView.visibleContentRectIncludingScrollbars();
609 FloatPoint constrainedOrigin = visibleContentRect.location();
610 constrainedOrigin.moveBy(-origin);
612 IntSize scaledTotalContentsSize = frameView.totalContentsSize();
613 scaledTotalContentsSize.scale(scale / m_webPage.pageScaleFactor());
615 // Scaling may have exposed the overhang area, so we need to constrain the final
616 // layer position exactly like scrolling will once it's committed, to ensure that
617 // scrolling doesn't make the view jump.
618 constrainedOrigin = ScrollableArea::constrainScrollPositionForOverhang(roundedIntRect(visibleContentRect), scaledTotalContentsSize, roundedIntPoint(constrainedOrigin), frameView.scrollOrigin(), frameView.headerHeight(), frameView.footerHeight());
619 constrainedOrigin.moveBy(-visibleContentRect.location());
620 constrainedOrigin = -constrainedOrigin;
622 if (m_transientZoomScale == scale && roundedIntPoint(m_transientZoomOrigin) == roundedIntPoint(constrainedOrigin)) {
623 // We're already at the right scale and position, so we don't need to animate.
624 applyTransientZoomToPage(scale, origin);
628 TransformationMatrix transform;
629 transform.translate(constrainedOrigin.x(), constrainedOrigin.y());
630 transform.scale(scale);
632 RetainPtr<CABasicAnimation> renderViewAnimationCA = transientZoomSnapAnimationForKeyPath("transform");
633 RefPtr<PlatformCAAnimation> renderViewAnimation = PlatformCAAnimationMac::create(renderViewAnimationCA.get());
634 renderViewAnimation->setToValue(transform);
636 RetainPtr<CALayer> shadowCALayer;
637 if (PlatformCALayer* shadowLayer = shadowLayerForTransientZoom())
638 shadowCALayer = shadowLayer->platformLayer();
640 RefPtr<PlatformCALayer> zoomLayer = layerForTransientZoom();
641 RefPtr<WebPage> page = &m_webPage;
643 [CATransaction begin];
644 [CATransaction setCompletionBlock:[zoomLayer, shadowCALayer, page, scale, origin] () {
645 zoomLayer->removeAnimationForKey("transientZoomCommit");
647 [shadowCALayer removeAllAnimations];
649 if (TiledCoreAnimationDrawingArea* drawingArea = static_cast<TiledCoreAnimationDrawingArea*>(page->drawingArea()))
650 drawingArea->applyTransientZoomToPage(scale, origin);
653 zoomLayer->addAnimationForKey("transientZoomCommit", renderViewAnimation.get());
656 FloatRect shadowBounds = shadowLayerBoundsForFrame(frameView, scale);
657 RetainPtr<CGPathRef> shadowPath = adoptCF(CGPathCreateWithRect(shadowBounds, NULL)).get();
659 RetainPtr<CABasicAnimation> shadowBoundsAnimation = transientZoomSnapAnimationForKeyPath("bounds");
660 [shadowBoundsAnimation setToValue:[NSValue valueWithRect:shadowBounds]];
661 RetainPtr<CABasicAnimation> shadowPositionAnimation = transientZoomSnapAnimationForKeyPath("position");
662 [shadowPositionAnimation setToValue:[NSValue valueWithPoint:shadowLayerPositionForFrame(frameView, constrainedOrigin)]];
663 RetainPtr<CABasicAnimation> shadowPathAnimation = transientZoomSnapAnimationForKeyPath("shadowPath");
664 [shadowPathAnimation setToValue:(id)shadowPath.get()];
666 [shadowCALayer addAnimation:shadowBoundsAnimation.get() forKey:@"transientZoomCommitShadowBounds"];
667 [shadowCALayer addAnimation:shadowPositionAnimation.get() forKey:@"transientZoomCommitShadowPosition"];
668 [shadowCALayer addAnimation:shadowPathAnimation.get() forKey:@"transientZoomCommitShadowPath"];
671 [CATransaction commit];
674 void TiledCoreAnimationDrawingArea::applyTransientZoomToPage(double scale, FloatPoint origin)
676 // If the page scale is already the target scale, setPageScaleFactor() will short-circuit
677 // and not apply the transform, so we can't depend on it to do so.
678 TransformationMatrix finalTransform;
679 finalTransform.scale(scale);
680 layerForTransientZoom()->setTransform(finalTransform);
682 FrameView& frameView = *m_webPage.mainFrameView();
684 if (PlatformCALayer* shadowLayer = shadowLayerForTransientZoom()) {
685 shadowLayer->setBounds(shadowLayerBoundsForFrame(frameView, 1));
686 shadowLayer->setPosition(shadowLayerPositionForFrame(frameView, FloatPoint()));
689 FloatPoint unscrolledOrigin(origin);
690 FloatRect unobscuredContentRect = frameView.unobscuredContentRectIncludingScrollbars();
691 unscrolledOrigin.moveBy(-unobscuredContentRect.location());
692 m_webPage.scalePage(scale, roundedIntPoint(-unscrolledOrigin));
693 m_transientZoomScale = 1;
697 } // namespace WebKit
699 #endif // !PLATFORM(IOS)