michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef GFX_ASYNCCOMPOSITIONMANAGER_H michael@0: #define GFX_ASYNCCOMPOSITIONMANAGER_H michael@0: michael@0: #include "Units.h" // for LayerPoint, etc michael@0: #include "mozilla/layers/LayerManagerComposite.h" // for LayerManagerComposite michael@0: #include "gfx3DMatrix.h" // for gfx3DMatrix michael@0: #include "mozilla/Attributes.h" // for MOZ_DELETE, MOZ_FINAL, etc michael@0: #include "mozilla/RefPtr.h" // for RefCounted michael@0: #include "mozilla/TimeStamp.h" // for TimeStamp michael@0: #include "mozilla/dom/ScreenOrientation.h" // for ScreenOrientation michael@0: #include "mozilla/gfx/BasePoint.h" // for BasePoint michael@0: #include "mozilla/layers/LayersMessages.h" // for TargetConfig michael@0: #include "nsAutoPtr.h" // for nsRefPtr michael@0: #include "nsISupportsImpl.h" // for LayerManager::AddRef, etc michael@0: michael@0: namespace mozilla { michael@0: namespace layers { michael@0: michael@0: class AsyncPanZoomController; michael@0: class Layer; michael@0: class LayerManagerComposite; michael@0: class AutoResolveRefLayers; michael@0: michael@0: // Represents (affine) transforms that are calculated from a content view. michael@0: struct ViewTransform { michael@0: ViewTransform(LayerPoint aTranslation = LayerPoint(), michael@0: ParentLayerToScreenScale aScale = ParentLayerToScreenScale()) michael@0: : mTranslation(aTranslation) michael@0: , mScale(aScale) michael@0: {} michael@0: michael@0: operator gfx3DMatrix() const michael@0: { michael@0: return michael@0: gfx3DMatrix::Translation(mTranslation.x, mTranslation.y, 0) * michael@0: gfx3DMatrix::ScalingMatrix(mScale.scale, mScale.scale, 1); michael@0: } michael@0: michael@0: bool operator==(const ViewTransform& rhs) const { michael@0: return mTranslation == rhs.mTranslation && mScale == rhs.mScale; michael@0: } michael@0: michael@0: bool operator!=(const ViewTransform& rhs) const { michael@0: return !(*this == rhs); michael@0: } michael@0: michael@0: LayerPoint mTranslation; michael@0: ParentLayerToScreenScale mScale; michael@0: }; michael@0: michael@0: /** michael@0: * Manage async composition effects. This class is only used with OMTC and only michael@0: * lives on the compositor thread. It is a layer on top of the layer manager michael@0: * (LayerManagerComposite) which deals with elements of composition which are michael@0: * usually dealt with by dom or layout when main thread rendering, but which can michael@0: * short circuit that stuff to directly affect layers as they are composited, michael@0: * for example, off-main thread animation, async video, async pan/zoom. michael@0: */ michael@0: class AsyncCompositionManager MOZ_FINAL michael@0: { michael@0: friend class AutoResolveRefLayers; michael@0: public: michael@0: NS_INLINE_DECL_REFCOUNTING(AsyncCompositionManager) michael@0: michael@0: AsyncCompositionManager(LayerManagerComposite* aManager) michael@0: : mLayerManager(aManager) michael@0: , mIsFirstPaint(false) michael@0: , mLayersUpdated(false) michael@0: , mReadyForCompose(true) michael@0: { michael@0: } michael@0: ~AsyncCompositionManager() michael@0: { michael@0: } michael@0: michael@0: /** michael@0: * This forces the is-first-paint flag to true. This is intended to michael@0: * be called by the widget code when it loses its viewport information michael@0: * (or for whatever reason wants to refresh the viewport information). michael@0: * The information refresh happens because the compositor will call michael@0: * SetFirstPaintViewport on the next frame of composition. michael@0: */ michael@0: void ForceIsFirstPaint() { mIsFirstPaint = true; } michael@0: michael@0: // Sample transforms for layer trees. Return true to request michael@0: // another animation frame. michael@0: bool TransformShadowTree(TimeStamp aCurrentFrame); michael@0: michael@0: // Calculates the correct rotation and applies the transform to michael@0: // our layer manager michael@0: void ComputeRotation(); michael@0: michael@0: // Call after updating our layer tree. michael@0: void Updated(bool isFirstPaint, const TargetConfig& aTargetConfig) michael@0: { michael@0: mIsFirstPaint |= isFirstPaint; michael@0: mLayersUpdated = true; michael@0: mTargetConfig = aTargetConfig; michael@0: } michael@0: michael@0: bool RequiresReorientation(mozilla::dom::ScreenOrientation aOrientation) michael@0: { michael@0: return mTargetConfig.orientation() != aOrientation; michael@0: } michael@0: michael@0: // True if the underlying layer tree is ready to be composited. michael@0: bool ReadyForCompose() { return mReadyForCompose; } michael@0: michael@0: // Returns true if the next composition will be the first for a michael@0: // particular document. michael@0: bool IsFirstPaint() { return mIsFirstPaint; } michael@0: michael@0: private: michael@0: void TransformScrollableLayer(Layer* aLayer); michael@0: // Return true if an AsyncPanZoomController content transform was michael@0: // applied for |aLayer|. *aWantNextFrame is set to true if the michael@0: // controller wants another animation frame. michael@0: bool ApplyAsyncContentTransformToTree(TimeStamp aCurrentFrame, Layer* aLayer, michael@0: bool* aWantNextFrame); michael@0: /** michael@0: * Update the shadow transform for aLayer assuming that is a scrollbar, michael@0: * so that it stays in sync with the content that is being scrolled by APZ. michael@0: */ michael@0: void ApplyAsyncTransformToScrollbar(TimeStamp aCurrentFrame, ContainerLayer* aLayer); michael@0: michael@0: void SetFirstPaintViewport(const LayerIntPoint& aOffset, michael@0: const CSSToLayerScale& aZoom, michael@0: const CSSRect& aCssPageRect); michael@0: void SetPageRect(const CSSRect& aCssPageRect); michael@0: void SyncViewportInfo(const LayerIntRect& aDisplayPort, michael@0: const CSSToLayerScale& aDisplayResolution, michael@0: bool aLayersUpdated, michael@0: ScreenPoint& aScrollOffset, michael@0: CSSToScreenScale& aScale, michael@0: LayerMargin& aFixedLayerMargins, michael@0: ScreenPoint& aOffset); michael@0: void SyncFrameMetrics(const ScreenPoint& aScrollOffset, michael@0: float aZoom, michael@0: const CSSRect& aCssPageRect, michael@0: bool aLayersUpdated, michael@0: const CSSRect& aDisplayPort, michael@0: const CSSToLayerScale& aDisplayResolution, michael@0: bool aIsFirstPaint, michael@0: LayerMargin& aFixedLayerMargins, michael@0: ScreenPoint& aOffset); michael@0: michael@0: /** michael@0: * Adds a translation to the transform of any fixed position (whose parent michael@0: * layer is not fixed) or sticky position layer descendant of michael@0: * aTransformedSubtreeRoot. The translation is chosen so that the layer's michael@0: * anchor point relative to aTransformedSubtreeRoot's parent layer is the same michael@0: * as it was when aTransformedSubtreeRoot's GetLocalTransform() was michael@0: * aPreviousTransformForRoot. For sticky position layers, the translation is michael@0: * further intersected with the layer's sticky scroll ranges. michael@0: * This function will also adjust layers so that the given content document michael@0: * fixed position margins will be respected during asynchronous panning and michael@0: * zooming. michael@0: */ michael@0: void AlignFixedAndStickyLayers(Layer* aLayer, Layer* aTransformedSubtreeRoot, michael@0: const gfx::Matrix4x4& aPreviousTransformForRoot, michael@0: const LayerMargin& aFixedLayerMargins); michael@0: michael@0: /** michael@0: * DRAWING PHASE ONLY michael@0: * michael@0: * For reach RefLayer in our layer tree, look up its referent and connect it michael@0: * to the layer tree, if found. michael@0: */ michael@0: void ResolveRefLayers(); michael@0: /** michael@0: * Detaches all referents resolved by ResolveRefLayers. michael@0: * Assumes that mLayerManager->GetRoot() and mTargetConfig have not changed michael@0: * since ResolveRefLayers was called. michael@0: */ michael@0: void DetachRefLayers(); michael@0: michael@0: TargetConfig mTargetConfig; michael@0: CSSRect mContentRect; michael@0: michael@0: nsRefPtr mLayerManager; michael@0: // When this flag is set, the next composition will be the first for a michael@0: // particular document (i.e. the document displayed on the screen will change). michael@0: // This happens when loading a new page or switching tabs. We notify the michael@0: // front-end (e.g. Java on Android) about this so that it take the new page michael@0: // size and zoom into account when providing us with the next view transform. michael@0: bool mIsFirstPaint; michael@0: michael@0: // This flag is set during a layers update, so that the first composition michael@0: // after a layers update has it set. It is cleared after that first composition. michael@0: bool mLayersUpdated; michael@0: michael@0: bool mReadyForCompose; michael@0: }; michael@0: michael@0: class MOZ_STACK_CLASS AutoResolveRefLayers { michael@0: public: michael@0: AutoResolveRefLayers(AsyncCompositionManager* aManager) : mManager(aManager) michael@0: { michael@0: if (mManager) { michael@0: mManager->ResolveRefLayers(); michael@0: } michael@0: } michael@0: michael@0: ~AutoResolveRefLayers() michael@0: { michael@0: if (mManager) { michael@0: mManager->DetachRefLayers(); michael@0: } michael@0: } michael@0: michael@0: private: michael@0: AsyncCompositionManager* mManager; michael@0: michael@0: AutoResolveRefLayers(const AutoResolveRefLayers&) MOZ_DELETE; michael@0: AutoResolveRefLayers& operator=(const AutoResolveRefLayers&) MOZ_DELETE; michael@0: }; michael@0: michael@0: } // layers michael@0: } // mozilla michael@0: michael@0: #endif