tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

WebRenderAPI.h (39568B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef MOZILLA_LAYERS_WEBRENDERAPI_H
      8 #define MOZILLA_LAYERS_WEBRENDERAPI_H
      9 
     10 #include <queue>
     11 #include <stdint.h>
     12 #include <vector>
     13 #include <unordered_map>
     14 
     15 #include "mozilla/AlreadyAddRefed.h"
     16 #include "mozilla/gfx/CompositorHitTestInfo.h"
     17 #include "mozilla/layers/AsyncImagePipelineOp.h"
     18 #include "mozilla/layers/IpcResourceUpdateQueue.h"
     19 #include "mozilla/layers/RemoteTextureMap.h"
     20 #include "mozilla/layers/ScrollableLayerGuid.h"
     21 #include "mozilla/layers/SyncObject.h"
     22 #include "mozilla/layers/CompositionRecorder.h"
     23 #include "mozilla/MozPromise.h"
     24 #include "mozilla/Range.h"
     25 #include "mozilla/TimeStamp.h"
     26 #include "mozilla/UniquePtr.h"
     27 #include "mozilla/VsyncDispatcher.h"
     28 #include "mozilla/webrender/webrender_ffi.h"
     29 #include "mozilla/webrender/WebRenderTypes.h"
     30 #include "nsString.h"
     31 #include "GLTypes.h"
     32 #include "Units.h"
     33 
     34 class gfxContext;
     35 
     36 #undef None
     37 
     38 namespace mozilla {
     39 
     40 class nsDisplayItem;
     41 class nsPaintedDisplayItem;
     42 class nsDisplayTransform;
     43 class nsDisplayListBuilder;
     44 struct DisplayItemClipChain;
     45 
     46 struct ActiveScrolledRoot;
     47 
     48 namespace widget {
     49 class CompositorWidget;
     50 }
     51 
     52 namespace layers {
     53 class CompositorBridgeParent;
     54 class DisplayItemCache;
     55 class WebRenderBridgeParent;
     56 class RenderRootStateManager;
     57 class StackingContextHelper;
     58 struct DisplayListData;
     59 }  // namespace layers
     60 
     61 namespace layout {
     62 class TextDrawTarget;
     63 }
     64 
     65 namespace wr {
     66 
     67 class DisplayListBuilder;
     68 class RendererOGL;
     69 class RendererEvent;
     70 class WebRenderAPI;
     71 
     72 // This isn't part of WR's API, but we define it here to simplify layout's
     73 // logic and data plumbing.
     74 struct Line {
     75  wr::LayoutRect bounds;
     76  float wavyLineThickness;
     77  wr::LineOrientation orientation;
     78  wr::ColorF color;
     79  wr::LineStyle style;
     80 };
     81 
     82 /// A handler that can be bundled into a transaction and notified at specific
     83 /// points in the rendering pipeline, such as after scene building or after
     84 /// frame building.
     85 ///
     86 /// If for any reason the handler is dropped before reaching the requested
     87 /// point, it is notified with the value Checkpoint::TransactionDropped.
     88 /// So it is safe to assume that the handler will be notified "at some point".
     89 class NotificationHandler {
     90 public:
     91  virtual void Notify(wr::Checkpoint aCheckpoint) = 0;
     92  virtual ~NotificationHandler() = default;
     93 };
     94 
     95 struct WrHitResult {
     96  layers::LayersId mLayersId;
     97  layers::ScrollableLayerGuid::ViewID mScrollId;
     98  gfx::CompositorHitTestInfo mHitInfo;
     99  SideBits mSideBits;
    100  Maybe<uint64_t> mAnimationId;
    101 };
    102 
    103 class TransactionBuilder final {
    104 public:
    105  explicit TransactionBuilder(
    106      WebRenderAPI* aApi, bool aUseSceneBuilderThread = true,
    107      layers::RemoteTextureTxnScheduler* aRemoteTextureTxnScheduler = nullptr,
    108      layers::RemoteTextureTxnId aRemoteTextureTxnId = 0);
    109 
    110  TransactionBuilder(
    111      WebRenderAPI* aApi, Transaction* aTxn, bool aUseSceneBuilderThread,
    112      bool aOwnsData,
    113      layers::RemoteTextureTxnScheduler* aRemoteTextureTxnScheduler,
    114      layers::RemoteTextureTxnId aRemoteTextureTxnId);
    115 
    116  ~TransactionBuilder();
    117 
    118  void SetLowPriority(bool aIsLowPriority);
    119 
    120  void UpdateEpoch(PipelineId aPipelineId, Epoch aEpoch);
    121 
    122  void SetRootPipeline(PipelineId aPipelineId);
    123 
    124  void RemovePipeline(PipelineId aPipelineId);
    125 
    126  void SetDisplayList(Epoch aEpoch, wr::WrPipelineId pipeline_id,
    127                      wr::BuiltDisplayListDescriptor dl_descriptor,
    128                      wr::Vec<uint8_t>& dl_items_data,
    129                      wr::Vec<uint8_t>& dl_cache_data,
    130                      wr::Vec<uint8_t>& dl_spatial_tree);
    131 
    132  void ClearDisplayList(Epoch aEpoch, wr::WrPipelineId aPipeline);
    133 
    134  void GenerateFrame(const VsyncId& aVsyncId, bool aPresent, bool aTracked,
    135                     wr::RenderReasons aReasons);
    136 
    137  void InvalidateRenderedFrame(wr::RenderReasons aReasons);
    138 
    139  void SetDocumentView(const LayoutDeviceIntRect& aDocRect);
    140 
    141  bool IsEmpty() const;
    142 
    143  bool IsResourceUpdatesEmpty() const;
    144 
    145  bool IsRenderedFrameInvalidated() const;
    146 
    147  void AddImage(wr::ImageKey aKey, const ImageDescriptor& aDescriptor,
    148                wr::Vec<uint8_t>& aBytes);
    149 
    150  void AddBlobImage(wr::BlobImageKey aKey, const ImageDescriptor& aDescriptor,
    151                    uint16_t aTileSize, wr::Vec<uint8_t>& aBytes,
    152                    const wr::DeviceIntRect& aVisibleRect);
    153 
    154  void AddExternalImageBuffer(ImageKey key, const ImageDescriptor& aDescriptor,
    155                              ExternalImageId aHandle);
    156 
    157  void AddExternalImage(ImageKey key, const ImageDescriptor& aDescriptor,
    158                        ExternalImageId aExtID,
    159                        wr::ExternalImageType aImageType,
    160                        uint8_t aChannelIndex = 0, bool aNormalizedUvs = false);
    161 
    162  void UpdateImageBuffer(wr::ImageKey aKey, const ImageDescriptor& aDescriptor,
    163                         wr::Vec<uint8_t>& aBytes);
    164 
    165  void UpdateBlobImage(wr::BlobImageKey aKey,
    166                       const ImageDescriptor& aDescriptor,
    167                       wr::Vec<uint8_t>& aBytes,
    168                       const wr::DeviceIntRect& aVisibleRect,
    169                       const wr::LayoutIntRect& aDirtyRect);
    170 
    171  void UpdateExternalImage(ImageKey aKey, const ImageDescriptor& aDescriptor,
    172                           ExternalImageId aExtID,
    173                           wr::ExternalImageType aImageType,
    174                           uint8_t aChannelIndex = 0,
    175                           bool aNormalizedUvs = false);
    176 
    177  void UpdateExternalImageWithDirtyRect(
    178      ImageKey aKey, const ImageDescriptor& aDescriptor, ExternalImageId aExtID,
    179      wr::ExternalImageType aImageType, const wr::DeviceIntRect& aDirtyRect,
    180      uint8_t aChannelIndex = 0, bool aNormalizedUvs = false);
    181 
    182  void SetBlobImageVisibleArea(BlobImageKey aKey,
    183                               const wr::DeviceIntRect& aArea);
    184 
    185  void DeleteImage(wr::ImageKey aKey);
    186 
    187  void DeleteBlobImage(wr::BlobImageKey aKey);
    188 
    189  void AddSnapshotImage(wr::SnapshotImageKey aKey);
    190 
    191  void DeleteSnapshotImage(wr::SnapshotImageKey aKey);
    192 
    193  void AddRawFont(wr::FontKey aKey, wr::Vec<uint8_t>& aBytes, uint32_t aIndex);
    194 
    195  void AddFontDescriptor(wr::FontKey aKey, wr::Vec<uint8_t>& aBytes,
    196                         uint32_t aIndex);
    197 
    198  void DeleteFont(wr::FontKey aKey);
    199 
    200  void AddFontInstance(wr::FontInstanceKey aKey, wr::FontKey aFontKey,
    201                       float aGlyphSize,
    202                       const wr::FontInstanceOptions* aOptions,
    203                       const wr::FontInstancePlatformOptions* aPlatformOptions,
    204                       wr::Vec<uint8_t>& aVariations);
    205 
    206  void DeleteFontInstance(wr::FontInstanceKey aKey);
    207 
    208  void UpdateQualitySettings(bool aForceSubpixelAAWherePossible);
    209 
    210  void RenderOffscreen(wr::WrPipelineId aPipelineId);
    211 
    212  void Notify(wr::Checkpoint aWhen, UniquePtr<NotificationHandler> aHandler);
    213 
    214  void Clear();
    215 
    216  Transaction* Take();
    217 
    218  bool UseSceneBuilderThread() const { return mUseSceneBuilderThread; }
    219  layers::WebRenderBackend GetBackendType() { return mApiBackend; }
    220  Transaction* Raw() const { return mTxn; }
    221 
    222  const RefPtr<layers::RemoteTextureTxnScheduler> mRemoteTextureTxnScheduler;
    223  const layers::RemoteTextureTxnId mRemoteTextureTxnId;
    224 
    225 protected:
    226  Transaction* mTxn;
    227  bool mUseSceneBuilderThread;
    228  layers::WebRenderBackend mApiBackend;
    229  bool mOwnsData;
    230 };
    231 
    232 class TransactionWrapper final {
    233 public:
    234  explicit TransactionWrapper(Transaction* aTxn);
    235 
    236  void AppendDynamicProperties(
    237      const nsTArray<wr::WrOpacityProperty>& aOpacityArray,
    238      const nsTArray<wr::WrTransformProperty>& aTransformArray,
    239      const nsTArray<wr::WrColorProperty>& aColorArray);
    240  void AppendTransformProperties(
    241      const nsTArray<wr::WrTransformProperty>& aTransformArray);
    242  void UpdateScrollPosition(
    243      const wr::ExternalScrollId& aScrollId,
    244      const nsTArray<wr::SampledScrollOffset>& aSampledOffsets);
    245  void UpdateIsTransformAsyncZooming(uint64_t aAnimationId, bool aIsZooming);
    246  void AddMinimapData(const wr::ExternalScrollId& aScrollId,
    247                      const MinimapData& aMinimapData);
    248 
    249 private:
    250  Transaction* mTxn;
    251 };
    252 
    253 class WebRenderAPI final {
    254  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebRenderAPI);
    255 
    256 public:
    257  /// This can be called on the compositor thread only.
    258  static already_AddRefed<WebRenderAPI> Create(
    259      layers::CompositorBridgeParent* aBridge,
    260      RefPtr<widget::CompositorWidget>&& aWidget,
    261      const wr::WrWindowId& aWindowId, LayoutDeviceIntSize aSize,
    262      layers::WindowKind aWindowKind, nsACString& aError);
    263 
    264  already_AddRefed<WebRenderAPI> Clone();
    265 
    266  void DestroyRenderer();
    267 
    268  wr::WindowId GetId() const { return mId; }
    269 
    270  /// Do a non-blocking hit-testing query on a shared version of the hit
    271  /// testing information.
    272  std::vector<WrHitResult> HitTest(const wr::WorldPoint& aPoint);
    273 
    274  void SendTransaction(TransactionBuilder& aTxn);
    275 
    276  void SetFrameStartTime(const TimeStamp& aTime);
    277 
    278  void RunOnRenderThread(UniquePtr<RendererEvent> aEvent);
    279 
    280  void Readback(const TimeStamp& aStartTime, gfx::IntSize aSize,
    281                const gfx::SurfaceFormat& aFormat,
    282                const Range<uint8_t>& aBuffer, bool* aNeedsYFlip);
    283 
    284  void ClearAllCaches();
    285  void EnableNativeCompositor(bool aEnable);
    286  void SetBatchingLookback(uint32_t aCount);
    287  void SetBool(wr::BoolParameter, bool value);
    288  void SetInt(wr::IntParameter, int32_t value);
    289  void SetFloat(wr::FloatParameter, float value);
    290 
    291  void SetClearColor(const gfx::DeviceColor& aColor);
    292  void SetProfilerUI(const nsACString& aUIString);
    293 
    294  void Pause();
    295  bool Resume();
    296 
    297  void WakeSceneBuilder();
    298  void FlushSceneBuilder();
    299 
    300  void NotifyMemoryPressure();
    301  void AccumulateMemoryReport(wr::MemoryReport*);
    302 
    303  wr::WrIdNamespace GetNamespace();
    304  layers::WebRenderBackend GetBackendType() { return mBackend; }
    305  layers::WebRenderCompositor GetCompositorType() { return mCompositor; }
    306  uint32_t GetMaxTextureSize() const { return mMaxTextureSize; }
    307  bool GetUseANGLE() const { return mUseANGLE; }
    308  bool GetUseDComp() const { return mUseDComp; }
    309  bool GetUseLayerCompositor() const { return mUseLayerCompositor; }
    310  bool GetUseTripleBuffering() const { return mUseTripleBuffering; }
    311  bool SupportsExternalBufferTextures() const {
    312    return mSupportsExternalBufferTextures;
    313  }
    314  layers::SyncHandle GetSyncHandle() const { return mSyncHandle; }
    315 
    316  void Capture();
    317 
    318  void StartCaptureSequence(const nsACString& aPath, uint32_t aFlags);
    319  void StopCaptureSequence();
    320 
    321  void BeginRecording(const TimeStamp& aRecordingStart,
    322                      wr::PipelineId aRootPipelineId);
    323 
    324  typedef MozPromise<layers::FrameRecording, nsresult, true>
    325      EndRecordingPromise;
    326 
    327  RefPtr<EndRecordingPromise> EndRecording();
    328 
    329  layers::RemoteTextureInfoList* GetPendingRemoteTextureInfoList();
    330  layers::AsyncImagePipelineOps* GetPendingAsyncImagePipelineOps(
    331      TransactionBuilder& aTxn);
    332 
    333  void FlushPendingWrTransactionEventsWithoutWait();
    334  void FlushPendingWrTransactionEventsWithWait();
    335 
    336  wr::WebRenderAPI* GetRootAPI();
    337 
    338 protected:
    339  WebRenderAPI(wr::DocumentHandle* aHandle, wr::WindowId aId,
    340               layers::WebRenderBackend aBackend,
    341               layers::WebRenderCompositor aCompositor,
    342               uint32_t aMaxTextureSize, bool aUseANGLE, bool aUseDComp,
    343               bool aUseLayerCompositor, bool aUseTripleBuffering,
    344               bool aSupportsExternalBufferTextures,
    345               layers::SyncHandle aSyncHandle,
    346               wr::WebRenderAPI* aRootApi = nullptr,
    347               wr::WebRenderAPI* aRootDocumentApi = nullptr);
    348 
    349  ~WebRenderAPI();
    350 
    351  void WaitUntilPresentationFlushed();
    352 
    353  void UpdateDebugFlags(uint64_t aFlags);
    354  bool CheckIsRemoteTextureReady(layers::RemoteTextureInfoList* aList,
    355                                 const TimeStamp& aTimeStamp);
    356  void WaitRemoteTextureReady(layers::RemoteTextureInfoList* aList);
    357 
    358  enum class RemoteTextureWaitType : uint8_t {
    359    AsyncWait = 0,
    360    FlushWithWait = 1,
    361    FlushWithoutWait = 2
    362  };
    363 
    364  void HandleWrTransactionEvents(RemoteTextureWaitType aType);
    365 
    366  class WrTransactionEvent {
    367   public:
    368    enum class Tag {
    369      Transaction,
    370      PendingRemoteTextures,
    371      PendingAsyncImagePipelineOps,
    372    };
    373    const Tag mTag;
    374    const TimeStamp mTimeStamp;
    375 
    376   private:
    377    WrTransactionEvent(const Tag aTag,
    378                       UniquePtr<TransactionBuilder>&& aTransaction)
    379        : mTag(aTag),
    380          mTimeStamp(TimeStamp::Now()),
    381          mTransaction(std::move(aTransaction)) {
    382      MOZ_ASSERT(mTag == Tag::Transaction);
    383    }
    384    WrTransactionEvent(
    385        const Tag aTag,
    386        UniquePtr<layers::RemoteTextureInfoList>&& aPendingRemoteTextures)
    387        : mTag(aTag),
    388          mTimeStamp(TimeStamp::Now()),
    389          mPendingRemoteTextures(std::move(aPendingRemoteTextures)) {
    390      MOZ_ASSERT(mTag == Tag::PendingRemoteTextures);
    391    }
    392    WrTransactionEvent(const Tag aTag,
    393                       UniquePtr<layers::AsyncImagePipelineOps>&&
    394                           aPendingAsyncImagePipelineOps,
    395                       UniquePtr<TransactionBuilder>&& aTransaction)
    396        : mTag(aTag),
    397          mTimeStamp(TimeStamp::Now()),
    398          mPendingAsyncImagePipelineOps(
    399              std::move(aPendingAsyncImagePipelineOps)),
    400          mTransaction(std::move(aTransaction)) {
    401      MOZ_ASSERT(mTag == Tag::PendingAsyncImagePipelineOps);
    402    }
    403 
    404    UniquePtr<layers::RemoteTextureInfoList> mPendingRemoteTextures;
    405    UniquePtr<layers::AsyncImagePipelineOps> mPendingAsyncImagePipelineOps;
    406    UniquePtr<TransactionBuilder> mTransaction;
    407 
    408   public:
    409    static WrTransactionEvent Transaction(WebRenderAPI* aApi,
    410                                          TransactionBuilder& aTxn) {
    411      auto transaction = MakeUnique<TransactionBuilder>(
    412          aApi, aTxn.Take(), aTxn.UseSceneBuilderThread(), /* aOwnsData */ true,
    413          aTxn.mRemoteTextureTxnScheduler, aTxn.mRemoteTextureTxnId);
    414      return WrTransactionEvent(Tag::Transaction, std::move(transaction));
    415    }
    416 
    417    static WrTransactionEvent PendingRemoteTextures(
    418        UniquePtr<layers::RemoteTextureInfoList>&& aPendingRemoteTextures) {
    419      return WrTransactionEvent(Tag::PendingRemoteTextures,
    420                                std::move(aPendingRemoteTextures));
    421    }
    422 
    423    static WrTransactionEvent PendingAsyncImagePipelineOps(
    424        UniquePtr<layers::AsyncImagePipelineOps>&&
    425            aPendingAsyncImagePipelineOps,
    426        WebRenderAPI* aApi, const TransactionBuilder& aTxn) {
    427      auto transaction = MakeUnique<TransactionBuilder>(
    428          aApi, aTxn.Raw(), aTxn.UseSceneBuilderThread(), /* aOwnsData */ false,
    429          aTxn.mRemoteTextureTxnScheduler, aTxn.mRemoteTextureTxnId);
    430      return WrTransactionEvent(Tag::PendingAsyncImagePipelineOps,
    431                                std::move(aPendingAsyncImagePipelineOps),
    432                                std::move(transaction));
    433    }
    434 
    435    wr::Transaction* RawTransaction() {
    436      if (mTag == Tag::Transaction) {
    437        return mTransaction->Raw();
    438      }
    439      MOZ_ASSERT_UNREACHABLE("unexpected to be called");
    440      return nullptr;
    441    }
    442 
    443    TransactionBuilder* GetTransactionBuilder() {
    444      if (mTag == Tag::Transaction ||
    445          mTag == Tag::PendingAsyncImagePipelineOps) {
    446        return mTransaction.get();
    447      }
    448      MOZ_CRASH("Should not be called");
    449      return nullptr;
    450    }
    451 
    452    bool UseSceneBuilderThread() {
    453      if (mTag == Tag::Transaction) {
    454        return mTransaction->UseSceneBuilderThread();
    455      }
    456      MOZ_ASSERT_UNREACHABLE("unexpected to be called");
    457      return true;
    458    }
    459 
    460    layers::RemoteTextureInfoList* RemoteTextureInfoList() {
    461      if (mTag == Tag::PendingRemoteTextures) {
    462        MOZ_ASSERT(mPendingRemoteTextures);
    463        return mPendingRemoteTextures.get();
    464      }
    465      MOZ_ASSERT_UNREACHABLE("unexpected to be called");
    466      return nullptr;
    467    }
    468 
    469    layers::AsyncImagePipelineOps* AsyncImagePipelineOps() {
    470      if (mTag == Tag::PendingAsyncImagePipelineOps) {
    471        MOZ_ASSERT(mPendingAsyncImagePipelineOps);
    472        return mPendingAsyncImagePipelineOps.get();
    473      }
    474      MOZ_ASSERT_UNREACHABLE("unexpected to be called");
    475      return nullptr;
    476    }
    477  };
    478 
    479  wr::DocumentHandle* mDocHandle;
    480  wr::WindowId mId;
    481  layers::WebRenderBackend mBackend;
    482  layers::WebRenderCompositor mCompositor;
    483  int32_t mMaxTextureSize;
    484  bool mUseANGLE;
    485  bool mUseDComp;
    486  bool mUseLayerCompositor;
    487  bool mUseTripleBuffering;
    488  bool mSupportsExternalBufferTextures;
    489  bool mCaptureSequence;
    490  layers::SyncHandle mSyncHandle;
    491  bool mRendererDestroyed;
    492 
    493  UniquePtr<layers::RemoteTextureInfoList> mPendingRemoteTextureInfoList;
    494  UniquePtr<layers::AsyncImagePipelineOps> mPendingAsyncImagePipelineOps;
    495  std::queue<WrTransactionEvent> mPendingWrTransactionEvents;
    496 
    497  // We maintain alive the root api to know when to shut the render backend
    498  // down, and the root api for the document to know when to delete the
    499  // document. mRootApi is null for the api object that owns the channel (and is
    500  // responsible for shutting it down), and mRootDocumentApi is null for the api
    501  // object owning (and responsible for destroying) a given document. All api
    502  // objects in the same window use the same channel, and some api objects write
    503  // to the same document (but there is only one owner for each channel and for
    504  // each document).
    505  const RefPtr<wr::WebRenderAPI> mRootApi;
    506  const RefPtr<wr::WebRenderAPI> mRootDocumentApi;
    507 
    508  friend class DisplayListBuilder;
    509  friend class layers::WebRenderBridgeParent;
    510 };
    511 
    512 // This is a RAII class that automatically sends the transaction on
    513 // destruction. This is useful for code that has multiple exit points and we
    514 // want to ensure that the stuff accumulated in the transaction gets sent
    515 // regardless of which exit we take. Note that if the caller explicitly calls
    516 // mApi->SendTransaction() that's fine too because that empties out the
    517 // TransactionBuilder and leaves it as a valid empty transaction, so calling
    518 // SendTransaction on it again ends up being a no-op.
    519 class MOZ_RAII AutoTransactionSender {
    520 public:
    521  AutoTransactionSender(WebRenderAPI* aApi, TransactionBuilder* aTxn)
    522      : mApi(aApi), mTxn(aTxn) {
    523    MOZ_RELEASE_ASSERT(mApi);
    524    MOZ_RELEASE_ASSERT(aTxn);
    525  }
    526 
    527  ~AutoTransactionSender() { mApi->SendTransaction(*mTxn); }
    528 
    529 private:
    530  WebRenderAPI* mApi;
    531  TransactionBuilder* mTxn;
    532 };
    533 
    534 /**
    535 * A set of optional parameters for stacking context creation.
    536 */
    537 struct MOZ_STACK_CLASS StackingContextParams : public WrStackingContextParams {
    538  StackingContextParams()
    539      : WrStackingContextParams{
    540            WrStackingContextClip::None(),
    541            nullptr,
    542            nullptr,
    543            nullptr,
    544            nullptr,
    545            wr::TransformStyle::Flat,
    546            wr::WrReferenceFrameKind::Transform,
    547            false,
    548            false,
    549            false,
    550            nullptr,
    551            /* prim_flags = */ wr::PrimitiveFlags::IS_BACKFACE_VISIBLE,
    552            wr::MixBlendMode::Normal,
    553            wr::StackingContextFlags{0}} {}
    554 
    555  void SetPreserve3D(bool aPreserve) {
    556    transform_style =
    557        aPreserve ? wr::TransformStyle::Preserve3D : wr::TransformStyle::Flat;
    558  }
    559 
    560  // Fill this in only if this is for the root StackingContextHelper.
    561  nsIFrame* mRootReferenceFrame = nullptr;
    562  nsTArray<wr::FilterOp> mFilters;
    563  nsTArray<wr::WrFilterData> mFilterDatas;
    564  wr::LayoutRect mBounds = wr::ToLayoutRect(LayoutDeviceRect());
    565  const gfx::Matrix4x4* mBoundTransform = nullptr;
    566  const wr::WrTransformInfo* mTransformPtr = nullptr;
    567  nsDisplayTransform* mDeferredTransformItem = nullptr;
    568  // Whether the stacking context is possibly animated. This alters how
    569  // coordinates are transformed/snapped to invalidate less when transforms
    570  // change frequently.
    571  bool mAnimated = false;
    572  // Whether items should be rasterized in a local space that is (mostly)
    573  // invariant to transforms, i.e. disabling subpixel AA and screen space pixel
    574  // snapping on text runs that would only make sense in screen space.
    575  bool mRasterizeLocally = false;
    576 };
    577 
    578 /// This is a simple C++ wrapper around WrState defined in the rust bindings.
    579 /// We may want to turn this into a direct wrapper on top of
    580 /// WebRenderFrameBuilder instead, so the interface may change a bit.
    581 class DisplayListBuilder final {
    582 public:
    583  explicit DisplayListBuilder(wr::PipelineId aId,
    584                              layers::WebRenderBackend aBackend);
    585  DisplayListBuilder(DisplayListBuilder&&) = default;
    586 
    587  ~DisplayListBuilder();
    588 
    589  void Save();
    590  void Restore();
    591  void ClearSave();
    592 
    593  usize Dump(usize aIndent, const Maybe<usize>& aStart,
    594             const Maybe<usize>& aEnd);
    595  void DumpSerializedDisplayList();
    596 
    597  void Begin(layers::DisplayItemCache* aCache = nullptr);
    598  void End(wr::BuiltDisplayList& aOutDisplayList);
    599  void End(layers::DisplayListData& aOutTransaction);
    600 
    601  Maybe<wr::WrSpatialId> PushStackingContext(
    602      const StackingContextParams& aParams, const wr::LayoutRect& aBounds,
    603      const wr::RasterSpace& aRasterSpace);
    604  void PopStackingContext(bool aIsReferenceFrame);
    605 
    606  wr::WrClipChainId DefineClipChain(Span<const wr::WrClipId> aClips,
    607                                    const Maybe<wr::WrClipChainId>& aParent);
    608 
    609  wr::WrClipId DefineImageMaskClip(const wr::ImageMask& aMask,
    610                                   const nsTArray<wr::LayoutPoint>&,
    611                                   wr::FillRule);
    612  wr::WrClipId DefineRoundedRectClip(Maybe<wr::WrSpatialId> aSpace,
    613                                     const wr::ComplexClipRegion& aComplex);
    614  wr::WrClipId DefineRectClip(Maybe<wr::WrSpatialId> aSpace,
    615                              wr::LayoutRect aClipRect);
    616 
    617  wr::WrSpatialId DefineStickyFrame(
    618      const ActiveScrolledRoot* aStickyAsr,
    619      Maybe<wr::WrSpatialId> aParentSpatialId,
    620      const wr::LayoutRect& aContentRect, const float* aTopMargin,
    621      const float* aRightMargin, const float* aBottomMargin,
    622      const float* aLeftMargin, const StickyOffsetBounds& aVerticalBounds,
    623      const StickyOffsetBounds& aHorizontalBounds,
    624      const wr::LayoutVector2D& aAppliedOffset, wr::SpatialTreeItemKey aKey,
    625      const WrAnimationProperty* aAnimation);
    626 
    627  Maybe<wr::WrSpatialId> GetScrollIdForDefinedScrollLayer(
    628      layers::ScrollableLayerGuid::ViewID aViewId) const;
    629  Maybe<wr::WrSpatialId> GetSpatialIdForDefinedStickyLayer(
    630      const ActiveScrolledRoot* aASR) const;
    631  wr::WrSpatialId DefineScrollLayer(
    632      const layers::ScrollableLayerGuid::ViewID& aViewId,
    633      const Maybe<wr::WrSpatialId>& aParent, const wr::LayoutRect& aContentRect,
    634      const wr::LayoutRect& aClipRect, const wr::LayoutVector2D& aScrollOffset,
    635      wr::APZScrollGeneration aScrollOffsetGeneration,
    636      wr::HasScrollLinkedEffect aHasScrollLinkedEffect,
    637      wr::SpatialTreeItemKey aKey);
    638 
    639  void PushRect(const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
    640                bool aIsBackfaceVisible, bool aForceAntiAliasing,
    641                bool aIsCheckerboard, const wr::ColorF& aColor);
    642  void PushRectWithAnimation(const wr::LayoutRect& aBounds,
    643                             const wr::LayoutRect& aClip,
    644                             bool aIsBackfaceVisible, const wr::ColorF& aColor,
    645                             const WrAnimationProperty* aAnimation);
    646  void PushRoundedRect(const wr::LayoutRect& aBounds,
    647                       const wr::LayoutRect& aClip, bool aIsBackfaceVisible,
    648                       const wr::ColorF& aColor);
    649  void PushHitTest(const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
    650                   bool aIsBackfaceVisible,
    651                   const layers::ScrollableLayerGuid::ViewID& aScrollId,
    652                   const gfx::CompositorHitTestInfo& aHitInfo,
    653                   SideBits aSideBits);
    654 
    655  void PushBackdropFilter(const wr::LayoutRect& aBounds,
    656                          const wr::ComplexClipRegion& aRegion,
    657                          const nsTArray<wr::FilterOp>& aFilters,
    658                          const nsTArray<wr::WrFilterData>& aFilterDatas,
    659                          bool aIsBackfaceVisible);
    660 
    661  void PushLinearGradient(const wr::LayoutRect& aBounds,
    662                          const wr::LayoutRect& aClip, bool aIsBackfaceVisible,
    663                          const wr::LayoutPoint& aStartPoint,
    664                          const wr::LayoutPoint& aEndPoint,
    665                          const nsTArray<wr::GradientStop>& aStops,
    666                          wr::ExtendMode aExtendMode,
    667                          const wr::LayoutSize aTileSize,
    668                          const wr::LayoutSize aTileSpacing);
    669 
    670  void PushRadialGradient(const wr::LayoutRect& aBounds,
    671                          const wr::LayoutRect& aClip, bool aIsBackfaceVisible,
    672                          const wr::LayoutPoint& aCenter,
    673                          const wr::LayoutSize& aRadius,
    674                          const nsTArray<wr::GradientStop>& aStops,
    675                          wr::ExtendMode aExtendMode,
    676                          const wr::LayoutSize aTileSize,
    677                          const wr::LayoutSize aTileSpacing);
    678 
    679  void PushConicGradient(const wr::LayoutRect& aBounds,
    680                         const wr::LayoutRect& aClip, bool aIsBackfaceVisible,
    681                         const wr::LayoutPoint& aCenter, const float aAngle,
    682                         const nsTArray<wr::GradientStop>& aStops,
    683                         wr::ExtendMode aExtendMode,
    684                         const wr::LayoutSize aTileSize,
    685                         const wr::LayoutSize aTileSpacing);
    686 
    687  void PushImage(const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
    688                 bool aIsBackfaceVisible, bool aForceAntiAliasing,
    689                 wr::ImageRendering aFilter, wr::ImageKey aImage,
    690                 bool aPremultipliedAlpha = true,
    691                 const wr::ColorF& aColor = wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f},
    692                 bool aPreferCompositorSurface = false,
    693                 bool aSupportsExternalCompositing = false);
    694 
    695  void PushRepeatingImage(
    696      const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
    697      bool aIsBackfaceVisible, const wr::LayoutSize& aStretchSize,
    698      const wr::LayoutSize& aTileSpacing, wr::ImageRendering aFilter,
    699      wr::ImageKey aImage, bool aPremultipliedAlpha = true,
    700      const wr::ColorF& aColor = wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f});
    701 
    702  void PushYCbCrPlanarImage(
    703      const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
    704      bool aIsBackfaceVisible, wr::ImageKey aImageChannel0,
    705      wr::ImageKey aImageChannel1, wr::ImageKey aImageChannel2,
    706      wr::WrColorDepth aColorDepth, wr::WrYuvColorSpace aColorSpace,
    707      wr::WrColorRange aColorRange, wr::ImageRendering aFilter,
    708      bool aPreferCompositorSurface = false,
    709      bool aSupportsExternalCompositing = false);
    710 
    711  void PushNV12Image(const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
    712                     bool aIsBackfaceVisible, wr::ImageKey aImageChannel0,
    713                     wr::ImageKey aImageChannel1, wr::WrColorDepth aColorDepth,
    714                     wr::WrYuvColorSpace aColorSpace,
    715                     wr::WrColorRange aColorRange, wr::ImageRendering aFilter,
    716                     bool aPreferCompositorSurface = false,
    717                     bool aSupportsExternalCompositing = false);
    718 
    719  void PushP010Image(const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
    720                     bool aIsBackfaceVisible, wr::ImageKey aImageChannel0,
    721                     wr::ImageKey aImageChannel1, wr::WrColorDepth aColorDepth,
    722                     wr::WrYuvColorSpace aColorSpace,
    723                     wr::WrColorRange aColorRange, wr::ImageRendering aFilter,
    724                     bool aPreferCompositorSurface = false,
    725                     bool aSupportsExternalCompositing = false);
    726 
    727  void PushNV16Image(const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
    728                     bool aIsBackfaceVisible, wr::ImageKey aImageChannel0,
    729                     wr::ImageKey aImageChannel1, wr::WrColorDepth aColorDepth,
    730                     wr::WrYuvColorSpace aColorSpace,
    731                     wr::WrColorRange aColorRange, wr::ImageRendering aFilter,
    732                     bool aPreferCompositorSurface = false,
    733                     bool aSupportsExternalCompositing = false);
    734 
    735  void PushYCbCrInterleavedImage(
    736      const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
    737      bool aIsBackfaceVisible, wr::ImageKey aImageChannel0,
    738      wr::WrColorDepth aColorDepth, wr::WrYuvColorSpace aColorSpace,
    739      wr::WrColorRange aColorRange, wr::ImageRendering aFilter,
    740      bool aPreferCompositorSurface = false,
    741      bool aSupportsExternalCompositing = false);
    742 
    743  void PushIFrame(const LayoutDeviceRect& aDevPxBounds, bool aIsBackfaceVisible,
    744                  wr::PipelineId aPipeline, bool aIgnoreMissingPipeline);
    745 
    746  // XXX WrBorderSides are passed with Range.
    747  // It is just to bypass compiler bug. See Bug 1357734.
    748  void PushBorder(const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
    749                  bool aIsBackfaceVisible, const wr::LayoutSideOffsets& aWidths,
    750                  const Range<const wr::BorderSide>& aSides,
    751                  const wr::BorderRadius& aRadius,
    752                  wr::AntialiasBorder = wr::AntialiasBorder::Yes);
    753 
    754  void PushBorderImage(const wr::LayoutRect& aBounds,
    755                       const wr::LayoutRect& aClip, bool aIsBackfaceVisible,
    756                       const wr::WrBorderImage& aParams);
    757 
    758  void PushBorderGradient(const wr::LayoutRect& aBounds,
    759                          const wr::LayoutRect& aClip, bool aIsBackfaceVisible,
    760                          const wr::LayoutSideOffsets& aWidths,
    761                          const int32_t aWidth, const int32_t aHeight,
    762                          bool aFill, const wr::DeviceIntSideOffsets& aSlice,
    763                          const wr::LayoutPoint& aStartPoint,
    764                          const wr::LayoutPoint& aEndPoint,
    765                          const nsTArray<wr::GradientStop>& aStops,
    766                          wr::ExtendMode aExtendMode);
    767 
    768  void PushBorderRadialGradient(
    769      const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
    770      bool aIsBackfaceVisible, const wr::LayoutSideOffsets& aWidths, bool aFill,
    771      const wr::LayoutPoint& aCenter, const wr::LayoutSize& aRadius,
    772      const nsTArray<wr::GradientStop>& aStops, wr::ExtendMode aExtendMode);
    773 
    774  void PushBorderConicGradient(
    775      const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
    776      bool aIsBackfaceVisible, const wr::LayoutSideOffsets& aWidths, bool aFill,
    777      const wr::LayoutPoint& aCenter, const float aAngle,
    778      const nsTArray<wr::GradientStop>& aStops, wr::ExtendMode aExtendMode);
    779 
    780  void PushText(const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
    781                bool aIsBackfaceVisible, const wr::ColorF& aColor,
    782                wr::FontInstanceKey aFontKey,
    783                Range<const wr::GlyphInstance> aGlyphBuffer,
    784                const wr::GlyphOptions* aGlyphOptions = nullptr);
    785 
    786  void PushLine(const wr::LayoutRect& aClip, bool aIsBackfaceVisible,
    787                const wr::Line& aLine);
    788 
    789  void PushShadow(const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
    790                  bool aIsBackfaceVisible, const wr::Shadow& aShadow,
    791                  bool aShouldInflate);
    792 
    793  void PopAllShadows();
    794 
    795  void PushBoxShadow(const wr::LayoutRect& aRect, const wr::LayoutRect& aClip,
    796                     bool aIsBackfaceVisible, const wr::LayoutRect& aBoxBounds,
    797                     const wr::LayoutVector2D& aOffset,
    798                     const wr::ColorF& aColor, const float& aBlurRadius,
    799                     const float& aSpreadRadius,
    800                     const wr::BorderRadius& aBorderRadius,
    801                     const wr::BoxShadowClipMode& aClipMode);
    802 
    803  void PushDebug(uint32_t aVal);
    804 
    805  /**
    806   * Notifies the DisplayListBuilder that it can group together WR display items
    807   * that are pushed until |CancelGroup()| or |FinishGroup()| call.
    808   */
    809  void StartGroup(nsPaintedDisplayItem* aItem);
    810 
    811  /**
    812   * Cancels grouping of the display items and discards all the display items
    813   * pushed between the |StartGroup()| and |CancelGroup()| calls.
    814   */
    815  void CancelGroup(const bool aDiscard = false);
    816 
    817  /**
    818   * Finishes the display item group. The group is stored in WebRender backend,
    819   * and can be reused with |ReuseItem()|, if the Gecko display item is reused.
    820   */
    821  void FinishGroup();
    822 
    823  /**
    824   * Try to reuse the previously created WebRender display items for the given
    825   * Gecko display item |aItem|.
    826   * Returns true if the items were reused, otherwise returns false.
    827   */
    828  bool ReuseItem(nsPaintedDisplayItem* aItem);
    829 
    830  uint64_t CurrentClipChainId() const {
    831    return mCurrentSpaceAndClipChain.clip_chain;
    832  }
    833 
    834  Maybe<wr::WrClipChainId> CurrentClipChainIdIfNotRoot() const {
    835    return mCurrentSpaceAndClipChain.clip_chain != wr::ROOT_CLIP_CHAIN
    836               ? Some(mCurrentSpaceAndClipChain.clip_chain)
    837               : Nothing();
    838  }
    839 
    840  const wr::WrSpaceAndClipChain& CurrentSpaceAndClipChain() const {
    841    return mCurrentSpaceAndClipChain;
    842  }
    843 
    844  const wr::PipelineId& CurrentPipelineId() const { return mPipelineId; }
    845  layers::WebRenderBackend GetBackendType() const { return mBackend; }
    846 
    847  // Checks to see if the innermost enclosing fixed pos item has the same
    848  // ASR. If so, it returns the scroll target for that fixed-pos item.
    849  // Otherwise, it returns Nothing().
    850  Maybe<layers::ScrollableLayerGuid::ViewID> GetContainingFixedPosScrollTarget(
    851      const ActiveScrolledRoot* aAsr);
    852 
    853  Maybe<SideBits> GetContainingFixedPosSideBits(const ActiveScrolledRoot* aAsr);
    854 
    855  gfxContext* GetTextContext(wr::IpcResourceUpdateQueue& aResources,
    856                             const layers::StackingContextHelper& aSc,
    857                             layers::RenderRootStateManager* aManager,
    858                             nsDisplayItem* aItem, nsRect& aBounds,
    859                             const gfx::Point& aDeviceOffset);
    860 
    861  // Try to avoid using this when possible.
    862  wr::WrState* Raw() { return mWrState; }
    863 
    864  void SetClipChainLeaf(const Maybe<wr::LayoutRect>& aClipRect) {
    865    mClipChainLeaf = aClipRect;
    866  }
    867 
    868  // Used for opacity flattening. When we flatten away an opacity item,
    869  // we push the opacity value onto the builder.
    870  // Descendant items should pull the inherited opacity during
    871  // their CreateWebRenderCommands implementation. This can only happen if all
    872  // descendant items reported supporting this functionality, via
    873  // nsDisplayItem::CanApplyOpacity.
    874  float GetInheritedOpacity() { return mInheritedOpacity; }
    875  void SetInheritedOpacity(float aOpacity) { mInheritedOpacity = aOpacity; }
    876  const DisplayItemClipChain* GetInheritedClipChain() {
    877    return mInheritedClipChain;
    878  }
    879  void PushInheritedClipChain(nsDisplayListBuilder* aBuilder,
    880                              const DisplayItemClipChain* aClipChain);
    881  void SetInheritedClipChain(const DisplayItemClipChain* aClipChain) {
    882    mInheritedClipChain = aClipChain;
    883  }
    884 
    885  layers::DisplayItemCache* GetDisplayItemCache() { return mDisplayItemCache; }
    886 
    887  // A chain of RAII objects, each holding a (ASR, ViewID, SideBits) tuple of
    888  // data. The topmost object is pointed to by the mActiveFixedPosTracker
    889  // pointer in the wr::DisplayListBuilder.
    890  class MOZ_RAII FixedPosScrollTargetTracker final {
    891   public:
    892    FixedPosScrollTargetTracker(DisplayListBuilder& aBuilder,
    893                                const ActiveScrolledRoot* aAsr,
    894                                layers::ScrollableLayerGuid::ViewID aScrollId,
    895                                SideBits aSideBits);
    896    ~FixedPosScrollTargetTracker();
    897    Maybe<layers::ScrollableLayerGuid::ViewID> GetScrollTargetForASR(
    898        const ActiveScrolledRoot* aAsr);
    899    Maybe<SideBits> GetSideBitsForASR(const ActiveScrolledRoot* aAsr);
    900 
    901   private:
    902    FixedPosScrollTargetTracker* mParentTracker;
    903    DisplayListBuilder& mBuilder;
    904    const ActiveScrolledRoot* mAsr;
    905    layers::ScrollableLayerGuid::ViewID mScrollId;
    906    SideBits mSideBits;
    907  };
    908 
    909 protected:
    910  wr::LayoutRect MergeClipLeaf(const wr::LayoutRect& aClip) {
    911    if (mClipChainLeaf) {
    912      return wr::IntersectLayoutRect(*mClipChainLeaf, aClip);
    913    }
    914    return aClip;
    915  }
    916 
    917  // See the implementation of PushShadow for details on these methods.
    918  void SuspendClipLeafMerging();
    919  void ResumeClipLeafMerging();
    920 
    921  wr::WrState* mWrState;
    922 
    923  // Track each scroll id that we encountered. We use this structure to
    924  // ensure that we don't define a particular scroll layer multiple times,
    925  // as that results in undefined behaviour in WR.
    926  std::unordered_map<layers::ScrollableLayerGuid::ViewID, wr::WrSpatialId>
    927      mScrollIds;
    928 
    929  // Track spatial ids that we've created corresponding to ActiveScrolledRoot
    930  // objects. Currently only used for sticky ASRs.
    931  // FIXME(follow-up to bug 1730749): Use this for scroll ASRs as well,
    932  // replacing mScrollIds.
    933  std::unordered_map<const ActiveScrolledRoot*, wr::WrSpatialId>
    934      mASRToSpatialIdMap;
    935 
    936  wr::WrSpaceAndClipChain mCurrentSpaceAndClipChain;
    937 
    938  // Contains the current leaf of the clip chain to be merged with the
    939  // display item's clip rect when pushing an item. May be set to Nothing() if
    940  // there is no clip rect to merge with.
    941  Maybe<wr::LayoutRect> mClipChainLeaf;
    942 
    943  // Versions of the above that are on hold while SuspendClipLeafMerging is on
    944  // (see the implementation of PushShadow for details).
    945  Maybe<wr::WrSpaceAndClipChain> mSuspendedSpaceAndClipChain;
    946  Maybe<wr::LayoutRect> mSuspendedClipChainLeaf;
    947 
    948  RefPtr<layout::TextDrawTarget> mCachedTextDT;
    949  mozilla::UniquePtr<gfxContext> mCachedContext;
    950 
    951  FixedPosScrollTargetTracker* mActiveFixedPosTracker;
    952 
    953  wr::PipelineId mPipelineId;
    954  layers::WebRenderBackend mBackend;
    955 
    956  layers::DisplayItemCache* mDisplayItemCache;
    957  Maybe<uint16_t> mCurrentCacheSlot;
    958  float mInheritedOpacity = 1.0f;
    959  const DisplayItemClipChain* mInheritedClipChain = nullptr;
    960 
    961  friend class WebRenderAPI;
    962  friend class SpaceAndClipChainHelper;
    963 };
    964 
    965 // This is a RAII class that overrides the current Wr's SpatialId and
    966 // ClipChainId.
    967 class MOZ_RAII SpaceAndClipChainHelper final {
    968 public:
    969  SpaceAndClipChainHelper(DisplayListBuilder& aBuilder,
    970                          wr::WrSpaceAndClipChain aSpaceAndClipChain)
    971      : mBuilder(aBuilder),
    972        mOldSpaceAndClipChain(aBuilder.mCurrentSpaceAndClipChain) {
    973    aBuilder.mCurrentSpaceAndClipChain = aSpaceAndClipChain;
    974  }
    975  SpaceAndClipChainHelper(DisplayListBuilder& aBuilder,
    976                          wr::WrSpatialId aSpatialId)
    977      : mBuilder(aBuilder),
    978        mOldSpaceAndClipChain(aBuilder.mCurrentSpaceAndClipChain) {
    979    aBuilder.mCurrentSpaceAndClipChain.space = aSpatialId;
    980  }
    981  SpaceAndClipChainHelper(DisplayListBuilder& aBuilder,
    982                          wr::WrClipChainId aClipChainId)
    983      : mBuilder(aBuilder),
    984        mOldSpaceAndClipChain(aBuilder.mCurrentSpaceAndClipChain) {
    985    aBuilder.mCurrentSpaceAndClipChain.clip_chain = aClipChainId.id;
    986  }
    987 
    988  ~SpaceAndClipChainHelper() {
    989    mBuilder.mCurrentSpaceAndClipChain = mOldSpaceAndClipChain;
    990  }
    991 
    992 private:
    993  SpaceAndClipChainHelper(const SpaceAndClipChainHelper&) = delete;
    994 
    995  DisplayListBuilder& mBuilder;
    996  wr::WrSpaceAndClipChain mOldSpaceAndClipChain;
    997 };
    998 
    999 Maybe<wr::ImageFormat> SurfaceFormatToImageFormat(gfx::SurfaceFormat aFormat);
   1000 
   1001 }  // namespace wr
   1002 }  // namespace mozilla
   1003 
   1004 #endif