gfx/layers/ReadbackProcessor.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/layers/ReadbackProcessor.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,181 @@
     1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     1.5 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "ReadbackProcessor.h"
    1.10 +#include <sys/types.h>                  // for int32_t
    1.11 +#include "Layers.h"                     // for Layer, ThebesLayer, etc
    1.12 +#include "ReadbackLayer.h"              // for ReadbackLayer, ReadbackSink
    1.13 +#include "gfx3DMatrix.h"                // for gfx3DMatrix
    1.14 +#include "gfxColor.h"                   // for gfxRGBA
    1.15 +#include "gfxContext.h"                 // for gfxContext
    1.16 +#include "gfxRect.h"                    // for gfxRect
    1.17 +#include "mozilla/gfx/BasePoint.h"      // for BasePoint
    1.18 +#include "mozilla/gfx/BaseRect.h"       // for BaseRect
    1.19 +#include "nsAutoPtr.h"                  // for nsRefPtr, nsAutoPtr
    1.20 +#include "nsDebug.h"                    // for NS_ASSERTION
    1.21 +#include "nsISupportsImpl.h"            // for gfxContext::Release, etc
    1.22 +#include "nsPoint.h"                    // for nsIntPoint
    1.23 +#include "nsRegion.h"                   // for nsIntRegion
    1.24 +#include "nsSize.h"                     // for nsIntSize
    1.25 +
    1.26 +namespace mozilla {
    1.27 +namespace layers {
    1.28 +
    1.29 +void
    1.30 +ReadbackProcessor::BuildUpdates(ContainerLayer* aContainer)
    1.31 +{
    1.32 +  NS_ASSERTION(mAllUpdates.IsEmpty(), "Some updates not processed?");
    1.33 +
    1.34 +  if (!aContainer->mMayHaveReadbackChild)
    1.35 +    return;
    1.36 +
    1.37 +  aContainer->mMayHaveReadbackChild = false;
    1.38 +  // go backwards so the updates read from earlier layers are later in the
    1.39 +  // array.
    1.40 +  for (Layer* l = aContainer->GetLastChild(); l; l = l->GetPrevSibling()) {
    1.41 +    if (l->GetType() == Layer::TYPE_READBACK) {
    1.42 +      aContainer->mMayHaveReadbackChild = true;
    1.43 +      BuildUpdatesForLayer(static_cast<ReadbackLayer*>(l));
    1.44 +    }
    1.45 +  }
    1.46 +}
    1.47 +
    1.48 +static Layer*
    1.49 +FindBackgroundLayer(ReadbackLayer* aLayer, nsIntPoint* aOffset)
    1.50 +{
    1.51 +  gfx::Matrix transform;
    1.52 +  if (!aLayer->GetTransform().Is2D(&transform) ||
    1.53 +      transform.HasNonIntegerTranslation())
    1.54 +    return nullptr;
    1.55 +  nsIntPoint transformOffset(int32_t(transform._31), int32_t(transform._32));
    1.56 +
    1.57 +  for (Layer* l = aLayer->GetPrevSibling(); l; l = l->GetPrevSibling()) {
    1.58 +    gfx::Matrix backgroundTransform;
    1.59 +    if (!l->GetTransform().Is2D(&backgroundTransform) ||
    1.60 +        gfx::ThebesMatrix(backgroundTransform).HasNonIntegerTranslation())
    1.61 +      return nullptr;
    1.62 +
    1.63 +    nsIntPoint backgroundOffset(int32_t(backgroundTransform._31), int32_t(backgroundTransform._32));
    1.64 +    nsIntRect rectInBackground(transformOffset - backgroundOffset, aLayer->GetSize());
    1.65 +    const nsIntRegion& visibleRegion = l->GetEffectiveVisibleRegion();
    1.66 +    if (!visibleRegion.Intersects(rectInBackground))
    1.67 +      continue;
    1.68 +    // Since l is present in the background, from here on we either choose l
    1.69 +    // or nothing.
    1.70 +    if (!visibleRegion.Contains(rectInBackground))
    1.71 +      return nullptr;
    1.72 +
    1.73 +    if (l->GetEffectiveOpacity() != 1.0 ||
    1.74 +        !(l->GetContentFlags() & Layer::CONTENT_OPAQUE))
    1.75 +      return nullptr;
    1.76 +
    1.77 +    // cliprects are post-transform
    1.78 +    const nsIntRect* clipRect = l->GetEffectiveClipRect();
    1.79 +    if (clipRect && !clipRect->Contains(nsIntRect(transformOffset, aLayer->GetSize())))
    1.80 +      return nullptr;
    1.81 +
    1.82 +    Layer::LayerType type = l->GetType();
    1.83 +    if (type != Layer::TYPE_COLOR && type != Layer::TYPE_THEBES)
    1.84 +      return nullptr;
    1.85 +
    1.86 +    *aOffset = backgroundOffset - transformOffset;
    1.87 +    return l;
    1.88 +  }
    1.89 +
    1.90 +  return nullptr;
    1.91 +}
    1.92 +
    1.93 +void
    1.94 +ReadbackProcessor::BuildUpdatesForLayer(ReadbackLayer* aLayer)
    1.95 +{
    1.96 +  if (!aLayer->mSink)
    1.97 +    return;
    1.98 +
    1.99 +  nsIntPoint offset;
   1.100 +  Layer* newBackground = FindBackgroundLayer(aLayer, &offset);
   1.101 +  if (!newBackground) {
   1.102 +    aLayer->SetUnknown();
   1.103 +    return;
   1.104 +  }
   1.105 +
   1.106 +  if (newBackground->GetType() == Layer::TYPE_COLOR) {
   1.107 +    ColorLayer* colorLayer = static_cast<ColorLayer*>(newBackground);
   1.108 +    if (aLayer->mBackgroundColor != colorLayer->GetColor()) {
   1.109 +      aLayer->mBackgroundLayer = nullptr;
   1.110 +      aLayer->mBackgroundColor = colorLayer->GetColor();
   1.111 +      NS_ASSERTION(aLayer->mBackgroundColor.a == 1.0,
   1.112 +                   "Color layer said it was opaque!");
   1.113 +      nsRefPtr<gfxContext> ctx =
   1.114 +          aLayer->mSink->BeginUpdate(aLayer->GetRect(),
   1.115 +                                     aLayer->AllocateSequenceNumber());
   1.116 +      if (ctx) {
   1.117 +        ctx->SetColor(aLayer->mBackgroundColor);
   1.118 +        nsIntSize size = aLayer->GetSize();
   1.119 +        ctx->Rectangle(gfxRect(0, 0, size.width, size.height));
   1.120 +        ctx->Fill();
   1.121 +        aLayer->mSink->EndUpdate(ctx, aLayer->GetRect());
   1.122 +      }
   1.123 +    }
   1.124 +  } else {
   1.125 +    NS_ASSERTION(newBackground->AsThebesLayer(), "Must be ThebesLayer");
   1.126 +    ThebesLayer* thebesLayer = static_cast<ThebesLayer*>(newBackground);
   1.127 +    // updateRect is relative to the ThebesLayer
   1.128 +    nsIntRect updateRect = aLayer->GetRect() - offset;
   1.129 +    if (thebesLayer != aLayer->mBackgroundLayer ||
   1.130 +        offset != aLayer->mBackgroundLayerOffset) {
   1.131 +      aLayer->mBackgroundLayer = thebesLayer;
   1.132 +      aLayer->mBackgroundLayerOffset = offset;
   1.133 +      aLayer->mBackgroundColor = gfxRGBA(0,0,0,0);
   1.134 +      thebesLayer->SetUsedForReadback(true);
   1.135 +    } else {
   1.136 +      nsIntRegion invalid;
   1.137 +      invalid.Sub(updateRect, thebesLayer->GetValidRegion());
   1.138 +      updateRect = invalid.GetBounds();
   1.139 +    }
   1.140 +
   1.141 +    Update update = { aLayer, updateRect, aLayer->AllocateSequenceNumber() };
   1.142 +    mAllUpdates.AppendElement(update);
   1.143 +  }
   1.144 +}
   1.145 +
   1.146 +void
   1.147 +ReadbackProcessor::GetThebesLayerUpdates(ThebesLayer* aLayer,
   1.148 +                                         nsTArray<Update>* aUpdates,
   1.149 +                                         nsIntRegion* aUpdateRegion)
   1.150 +{
   1.151 +  // All ThebesLayers used for readback are in mAllUpdates (some possibly
   1.152 +  // with an empty update rect).
   1.153 +  aLayer->SetUsedForReadback(false);
   1.154 +  if (aUpdateRegion) {
   1.155 +    aUpdateRegion->SetEmpty();
   1.156 +  }
   1.157 +  for (uint32_t i = mAllUpdates.Length(); i > 0; --i) {
   1.158 +    const Update& update = mAllUpdates[i - 1];
   1.159 +    if (update.mLayer->mBackgroundLayer == aLayer) {
   1.160 +      aLayer->SetUsedForReadback(true);
   1.161 +      // Don't bother asking for updates if we have an empty update rect.
   1.162 +      if (!update.mUpdateRect.IsEmpty()) {
   1.163 +        aUpdates->AppendElement(update);
   1.164 +        if (aUpdateRegion) {
   1.165 +          aUpdateRegion->Or(*aUpdateRegion, update.mUpdateRect);
   1.166 +        }
   1.167 +      }
   1.168 +      mAllUpdates.RemoveElementAt(i - 1);
   1.169 +    }
   1.170 +  }
   1.171 +}
   1.172 +
   1.173 +ReadbackProcessor::~ReadbackProcessor()
   1.174 +{
   1.175 +  for (uint32_t i = mAllUpdates.Length(); i > 0; --i) {
   1.176 +    const Update& update = mAllUpdates[i - 1];
   1.177 +    // Unprocessed update. Notify the readback sink that this content is
   1.178 +    // unknown.
   1.179 +    update.mLayer->SetUnknown();
   1.180 +  }
   1.181 +}
   1.182 +
   1.183 +}
   1.184 +}

mercurial