static Layer*
FindBackgroundLayer(ReadbackLayer* aLayer, nsIntPoint* aOffset)
{
  gfx::Matrix transform;
  if (!aLayer->GetTransform().Is2D(&transform) ||
      transform.HasNonIntegerTranslation())
    return nullptr;
  nsIntPoint transformOffset(int32_t(transform._31), int32_t(transform._32));

  for (Layer* l = aLayer->GetPrevSibling(); l; l = l->GetPrevSibling()) {
    gfx::Matrix backgroundTransform;
    if (!l->GetTransform().Is2D(&backgroundTransform) ||
        gfx::ThebesMatrix(backgroundTransform).HasNonIntegerTranslation())
      return nullptr;

    nsIntPoint backgroundOffset(int32_t(backgroundTransform._31), int32_t(backgroundTransform._32));
    IntRect rectInBackground(transformOffset - backgroundOffset, aLayer->GetSize());
    const nsIntRegion visibleRegion = l->GetEffectiveVisibleRegion().ToUnknownRegion();
    if (!visibleRegion.Intersects(rectInBackground))
      continue;
    // Since l is present in the background, from here on we either choose l
    // or nothing.
    if (!visibleRegion.Contains(rectInBackground))
      return nullptr;

    if (l->GetEffectiveOpacity() != 1.0 ||
        l->HasMaskLayers() ||
        !(l->GetContentFlags() & Layer::CONTENT_OPAQUE))
    {
      return nullptr;
    }

    // cliprects are post-transform
    const Maybe<ParentLayerIntRect>& clipRect = l->GetEffectiveClipRect();
    if (clipRect && !clipRect->Contains(ViewAs<ParentLayerPixel>(IntRect(transformOffset, aLayer->GetSize()))))
      return nullptr;

    Layer::LayerType type = l->GetType();
    if (type != Layer::TYPE_COLOR && type != Layer::TYPE_PAINTED)
      return nullptr;

    *aOffset = backgroundOffset - transformOffset;
    return l;
  }

  return nullptr;
}
static Layer*
FindBackgroundLayer(ReadbackLayer* aLayer, nsIntPoint* aOffset)
{
  gfxMatrix transform;
  if (!aLayer->GetTransform().Is2D(&transform) ||
      transform.HasNonIntegerTranslation())
    return nullptr;
  nsIntPoint transformOffset(int32_t(transform.x0), int32_t(transform.y0));

  for (Layer* l = aLayer->GetPrevSibling(); l; l = l->GetPrevSibling()) {
    gfxMatrix backgroundTransform;
    if (!l->GetTransform().Is2D(&backgroundTransform) ||
        backgroundTransform.HasNonIntegerTranslation())
      return nullptr;

    nsIntPoint backgroundOffset(int32_t(backgroundTransform.x0), int32_t(backgroundTransform.y0));
    nsIntRect rectInBackground(transformOffset - backgroundOffset, aLayer->GetSize());
    const nsIntRegion& visibleRegion = l->GetEffectiveVisibleRegion();
    if (!visibleRegion.Intersects(rectInBackground))
      continue;
    // Since l is present in the background, from here on we either choose l
    // or nothing.
    if (!visibleRegion.Contains(rectInBackground))
      return nullptr;

    if (l->GetEffectiveOpacity() != 1.0 ||
        !(l->GetContentFlags() & Layer::CONTENT_OPAQUE))
      return nullptr;

    // cliprects are post-transform
    const nsIntRect* clipRect = l->GetEffectiveClipRect();
    if (clipRect && !clipRect->Contains(nsIntRect(transformOffset, aLayer->GetSize())))
      return nullptr;

    Layer::LayerType type = l->GetType();
    if (type != Layer::TYPE_COLOR && type != Layer::TYPE_THEBES)
      return nullptr;

    *aOffset = backgroundOffset - transformOffset;
    return l;
  }

  return nullptr;
}
bool
BasicContainerLayer::ChildrenPartitionVisibleRegion(const gfx::IntRect& aInRect)
{
  Matrix transform;
  if (!GetEffectiveTransform().CanDraw2D(&transform) ||
      ThebesMatrix(transform).HasNonIntegerTranslation())
    return false;

  nsIntPoint offset(int32_t(transform._31), int32_t(transform._32));
  gfx::IntRect rect = aInRect.Intersect(GetEffectiveVisibleRegion().GetBounds() + offset);
  nsIntRegion covered;

  for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) {
    if (ToData(l)->IsHidden())
      continue;

    Matrix childTransform;
    if (!l->GetEffectiveTransform().CanDraw2D(&childTransform) ||
        ThebesMatrix(childTransform).HasNonIntegerTranslation() ||
        l->GetEffectiveOpacity() != 1.0)
      return false;
    nsIntRegion childRegion = l->GetEffectiveVisibleRegion();
    childRegion.MoveBy(int32_t(childTransform._31), int32_t(childTransform._32));
    childRegion.And(childRegion, rect);
    if (l->GetClipRect()) {
      childRegion.And(childRegion, ParentLayerIntRect::ToUntyped(*l->GetClipRect()) + offset);
    }
    nsIntRegion intersection;
    intersection.And(covered, childRegion);
    if (!intersection.IsEmpty())
      return false;
    covered.Or(covered, childRegion);
  }

  return covered.Contains(rect);
}
bool
LayerMLGPU::PrepareToRender(FrameBuilder* aBuilder, const RenderTargetIntRect& aClipRect)
{
  if (mFrameKey == sFrameKey) {
    return mPrepared;
  }
  mFrameKey = sFrameKey;
  mPrepared = false;

  Layer* layer = GetLayer();

  // Only container layers may have mixed blend modes.
  MOZ_ASSERT_IF(layer->GetMixBlendMode() != CompositionOp::OP_OVER,
                layer->GetType() == Layer::TYPE_CONTAINER);

  mComputedClipRect = aClipRect;
  mComputedOpacity = layer->GetEffectiveOpacity();

  if (layer->HasMaskLayers()) {
    mMask = aBuilder->AddMaskOperation(this);
    // If the mask has no texture, the pixel shader can't read any non-zero
    // values for the mask, so we can consider the whole thing invisible.
    if (mMask && mMask->IsEmpty()) {
      mComputedOpacity = 0.0f;
    }
  } else {
    mMask = nullptr;
  }

  if (!OnPrepareToRender(aBuilder)) {
    return false;
  }

  mPrepared = true;
  return true;
}