예제 #1
0
/* static */ bool
HwcUtils::PrepareLayerRects(nsIntRect aVisible,
                            const gfx::Matrix& aLayerTransform,
                            const gfx::Matrix& aLayerBufferTransform,
                            nsIntRect aClip, nsIntRect aBufferRect,
                            bool aYFlipped,
                            hwc_rect_t* aSourceCrop, hwc_rect_t* aVisibleRegionScreen) {

    gfxMatrix aTransform = gfx::ThebesMatrix(aLayerTransform);
    gfxRect visibleRect(ThebesRect(aVisible));
    gfxRect clip(ThebesRect(aClip));
    gfxRect visibleRectScreen = aTransform.TransformBounds(visibleRect);
    // |clip| is guaranteed to be integer
    visibleRectScreen.IntersectRect(visibleRectScreen, clip);

    if (visibleRectScreen.IsEmpty()) {
        return false;
    }

    gfxMatrix inverse = gfx::ThebesMatrix(aLayerBufferTransform);
    inverse.Invert();
    gfxRect crop = inverse.TransformBounds(visibleRectScreen);

    //clip to buffer size
    crop.IntersectRect(crop, ThebesRect(aBufferRect));
    crop.Round();

    if (crop.IsEmpty()) {
        return false;
    }

    //propagate buffer clipping back to visible rect
    gfxMatrix layerBufferTransform = gfx::ThebesMatrix(aLayerBufferTransform);
    visibleRectScreen = layerBufferTransform.TransformBounds(crop);
    visibleRectScreen.Round();

    // Map from layer space to buffer space
    crop -= aBufferRect.TopLeft();
    if (aYFlipped) {
        crop.y = aBufferRect.height - (crop.y + crop.height);
    }

    aSourceCrop->left = crop.x;
    aSourceCrop->top  = crop.y;
    aSourceCrop->right  = crop.x + crop.width;
    aSourceCrop->bottom = crop.y + crop.height;

    aVisibleRegionScreen->left = visibleRectScreen.x;
    aVisibleRegionScreen->top  = visibleRectScreen.y;
    aVisibleRegionScreen->right  = visibleRectScreen.x + visibleRectScreen.width;
    aVisibleRegionScreen->bottom = visibleRectScreen.y + visibleRectScreen.height;

    return true;
}
예제 #2
0
/* static */ bool
HwcUtils::CalculateClipRect(const gfx::Matrix& transform,
                            const nsIntRect* aLayerClip,
                            nsIntRect aParentClip, nsIntRect* aRenderClip) {

    gfxMatrix aTransform = gfx::ThebesMatrix(transform);
    *aRenderClip = aParentClip;

    if (!aLayerClip) {
        return true;
    }

    if (aLayerClip->IsEmpty()) {
        return false;
    }

    nsIntRect clip = *aLayerClip;

    gfxRect r = ThebesRect(clip);
    gfxRect trClip = aTransform.TransformBounds(r);
    trClip.Round();
    gfxUtils::GfxRectToIntRect(trClip, &clip);

    aRenderClip->IntersectRect(*aRenderClip, clip);
    return true;
}
예제 #3
0
/* static */ bool
HwcUtils::PrepareVisibleRegion(const nsIntRegion& aVisible,
                               const gfx::Matrix& aLayerTransform,
                               const gfx::Matrix& aLayerBufferTransform,
                               nsIntRect aClip, nsIntRect aBufferRect,
                               RectVector* aVisibleRegionScreen,
                               bool& aIsVisible) {
    const float MIN_SRC_WIDTH = 2.f;
    const float MIN_SRC_HEIGHT = 2.f;

    gfxMatrix layerTransform = gfx::ThebesMatrix(aLayerTransform);
    gfxMatrix layerBufferTransform = gfx::ThebesMatrix(aLayerBufferTransform);
    gfxRect bufferRect =
        layerBufferTransform.TransformBounds(ThebesRect(aBufferRect));
    gfxMatrix inverse = gfx::ThebesMatrix(aLayerBufferTransform);
    inverse.Invert();
    nsIntRegionRectIterator rect(aVisible);
    aIsVisible = false;
    while (const nsIntRect* visibleRect = rect.Next()) {
        hwc_rect_t visibleRectScreen;
        gfxRect screenRect;

        screenRect = layerTransform.TransformBounds(ThebesRect(*visibleRect));
        screenRect.IntersectRect(screenRect, bufferRect);
        screenRect.IntersectRect(screenRect, ThebesRect(aClip));
        screenRect.Round();
        if (screenRect.IsEmpty()) {
            continue;
        }
        visibleRectScreen.left = screenRect.x;
        visibleRectScreen.top  = screenRect.y;
        visibleRectScreen.right  = screenRect.XMost();
        visibleRectScreen.bottom = screenRect.YMost();

        gfxRect srcCrop = inverse.TransformBounds(screenRect);
        // When src crop is very small, HWC could not render correctly in some cases.
        // See Bug 1169093
        if(srcCrop.Width() < MIN_SRC_WIDTH || srcCrop.Height() < MIN_SRC_HEIGHT) {
            return false;
        }

        aVisibleRegionScreen->push_back(visibleRectScreen);
        aIsVisible = true;
    }

    return true;
}
예제 #4
0
nsIntRect
Layer::CalculateScissorRect(const nsIntRect& aCurrentScissorRect,
                            const gfx::Matrix* aWorldTransform)
{
  ContainerLayer* container = GetParent();
  NS_ASSERTION(container, "This can't be called on the root!");

  // Establish initial clip rect: it's either the one passed in, or
  // if the parent has an intermediate surface, it's the extents of that surface.
  nsIntRect currentClip;
  if (container->UseIntermediateSurface()) {
    currentClip.SizeTo(container->GetIntermediateSurfaceRect().Size());
  } else {
    currentClip = aCurrentScissorRect;
  }

  const nsIntRect *clipRect = GetEffectiveClipRect();
  if (!clipRect)
    return currentClip;

  if (clipRect->IsEmpty()) {
    // We might have a non-translation transform in the container so we can't
    // use the code path below.
    return nsIntRect(currentClip.TopLeft(), nsIntSize(0, 0));
  }

  nsIntRect scissor = *clipRect;
  if (!container->UseIntermediateSurface()) {
    gfx::Matrix matrix;
    DebugOnly<bool> is2D = container->GetEffectiveTransform().Is2D(&matrix);
    // See DefaultComputeEffectiveTransforms below
    NS_ASSERTION(is2D && matrix.PreservesAxisAlignedRectangles(),
                 "Non preserves axis aligned transform with clipped child should have forced intermediate surface");
    gfx::Rect r(scissor.x, scissor.y, scissor.width, scissor.height);
    gfxRect trScissor = gfx::ThebesRect(matrix.TransformBounds(r));
    trScissor.Round();
    if (!gfxUtils::GfxRectToIntRect(trScissor, &scissor)) {
      return nsIntRect(currentClip.TopLeft(), nsIntSize(0, 0));
    }

    // Find the nearest ancestor with an intermediate surface
    do {
      container = container->GetParent();
    } while (container && !container->UseIntermediateSurface());
  }
  if (container) {
    scissor.MoveBy(-container->GetIntermediateSurfaceRect().TopLeft());
  } else if (aWorldTransform) {
    gfx::Rect r(scissor.x, scissor.y, scissor.width, scissor.height);
    gfx::Rect trScissor = aWorldTransform->TransformBounds(r);
    trScissor.Round();
    if (!gfxUtils::GfxRectToIntRect(ThebesRect(trScissor), &scissor))
      return nsIntRect(currentClip.TopLeft(), nsIntSize(0, 0));
  }
  return currentClip.Intersect(scissor);
}
static IntRect
TransformRect(const IntRect& aRect, const Matrix4x4& aTransform)
{
  if (aRect.IsEmpty()) {
    return IntRect();
  }

  Rect rect(aRect.x, aRect.y, aRect.width, aRect.height);
  rect = aTransform.TransformBounds(rect);
  rect.RoundOut();

  IntRect intRect;
  if (!gfxUtils::GfxRectToIntRect(ThebesRect(rect), &intRect)) {
    return IntRect();
  }

  return intRect;
}
예제 #6
0
static mozilla::gfx::IntRect
TransformRect(const mozilla::gfx::IntRect& aRect, const mozilla::gfx::Matrix4x4& aTransform)
{
    if (aRect.IsEmpty()) {
        return mozilla::gfx::IntRect();
    }

    mozilla::gfx::RectDouble rect(aRect.x, aRect.y, aRect.width, aRect.height);
    rect = aTransform.TransformAndClipBounds(rect, mozilla::gfx::RectDouble::MaxIntRect());
    rect.RoundOut();

    mozilla::gfx::IntRect intRect;
    if (!gfxUtils::GfxRectToIntRect(ThebesRect(rect), &intRect)) {
        return mozilla::gfx::IntRect();
    }

    return intRect;
}
예제 #7
0
void
BasicCompositor::DrawQuad(const gfx::Rect& aRect,
                          const gfx::Rect& aClipRect,
                          const EffectChain &aEffectChain,
                          gfx::Float aOpacity,
                          const gfx::Matrix4x4& aTransform,
                          const gfx::Rect& aVisibleRect)
{
  RefPtr<DrawTarget> buffer = mRenderTarget->mDrawTarget;

  // For 2D drawing, |dest| and |buffer| are the same surface. For 3D drawing,
  // |dest| is a temporary surface.
  RefPtr<DrawTarget> dest = buffer;

  buffer->PushClipRect(aClipRect);
  AutoRestoreTransform autoRestoreTransform(dest);

  Matrix newTransform;
  Rect transformBounds;
  gfx3DMatrix new3DTransform;
  IntPoint offset = mRenderTarget->GetOrigin();

  if (aTransform.Is2D()) {
    newTransform = aTransform.As2D();
  } else {
    // Create a temporary surface for the transform.
    dest = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(RoundOut(aRect).Size(), SurfaceFormat::B8G8R8A8);
    if (!dest) {
      return;
    }

    dest->SetTransform(Matrix::Translation(-aRect.x, -aRect.y));

    // Get the bounds post-transform.
    new3DTransform = To3DMatrix(aTransform);
    gfxRect bounds = new3DTransform.TransformBounds(ThebesRect(aRect));
    bounds.IntersectRect(bounds, gfxRect(offset.x, offset.y, buffer->GetSize().width, buffer->GetSize().height));

    transformBounds = ToRect(bounds);
    transformBounds.RoundOut();

    // Propagate the coordinate offset to our 2D draw target.
    newTransform = Matrix::Translation(transformBounds.x, transformBounds.y);

    // When we apply the 3D transformation, we do it against a temporary
    // surface, so undo the coordinate offset.
    new3DTransform = gfx3DMatrix::Translation(aRect.x, aRect.y, 0) * new3DTransform;
  }

  newTransform.PostTranslate(-offset.x, -offset.y);
  buffer->SetTransform(newTransform);

  RefPtr<SourceSurface> sourceMask;
  Matrix maskTransform;
  if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) {
    EffectMask *effectMask = static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EffectTypes::MASK].get());
    sourceMask = effectMask->mMaskTexture->AsSourceBasic()->GetSurface(dest);
    MOZ_ASSERT(effectMask->mMaskTransform.Is2D(), "How did we end up with a 3D transform here?!");
    MOZ_ASSERT(!effectMask->mIs3D);
    maskTransform = effectMask->mMaskTransform.As2D();
    maskTransform.PreTranslate(-offset.x, -offset.y);
  }

  switch (aEffectChain.mPrimaryEffect->mType) {
    case EffectTypes::SOLID_COLOR: {
      EffectSolidColor* effectSolidColor =
        static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get());

      FillRectWithMask(dest, aRect, effectSolidColor->mColor,
                       DrawOptions(aOpacity), sourceMask, &maskTransform);
      break;
    }
    case EffectTypes::RGB: {
      TexturedEffect* texturedEffect =
          static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
      TextureSourceBasic* source = texturedEffect->mTexture->AsSourceBasic();

      if (texturedEffect->mPremultiplied) {
          DrawSurfaceWithTextureCoords(dest, aRect,
                                       source->GetSurface(dest),
                                       texturedEffect->mTextureCoords,
                                       texturedEffect->mFilter,
                                       aOpacity, sourceMask, &maskTransform);
      } else {
          RefPtr<DataSourceSurface> srcData = source->GetSurface(dest)->GetDataSurface();

          // Yes, we re-create the premultiplied data every time.
          // This might be better with a cache, eventually.
          RefPtr<DataSourceSurface> premultData = gfxUtils::CreatePremultipliedDataSurface(srcData);

          DrawSurfaceWithTextureCoords(dest, aRect,
                                       premultData,
                                       texturedEffect->mTextureCoords,
                                       texturedEffect->mFilter,
                                       aOpacity, sourceMask, &maskTransform);
      }
      break;
    }
    case EffectTypes::YCBCR: {
      NS_RUNTIMEABORT("Can't (easily) support component alpha with BasicCompositor!");
      break;
    }
    case EffectTypes::RENDER_TARGET: {
      EffectRenderTarget* effectRenderTarget =
        static_cast<EffectRenderTarget*>(aEffectChain.mPrimaryEffect.get());
      RefPtr<BasicCompositingRenderTarget> surface
        = static_cast<BasicCompositingRenderTarget*>(effectRenderTarget->mRenderTarget.get());
      RefPtr<SourceSurface> sourceSurf = surface->mDrawTarget->Snapshot();

      DrawSurfaceWithTextureCoords(dest, aRect,
                                   sourceSurf,
                                   effectRenderTarget->mTextureCoords,
                                   effectRenderTarget->mFilter,
                                   aOpacity, sourceMask, &maskTransform);
      break;
    }
    case EffectTypes::COMPONENT_ALPHA: {
      NS_RUNTIMEABORT("Can't (easily) support component alpha with BasicCompositor!");
      break;
    }
    default: {
      NS_RUNTIMEABORT("Invalid effect type!");
      break;
    }
  }

  if (!aTransform.Is2D()) {
    dest->Flush();

    RefPtr<SourceSurface> snapshot = dest->Snapshot();
    RefPtr<DataSourceSurface> source = snapshot->GetDataSurface();
    RefPtr<DataSourceSurface> temp =
      Factory::CreateDataSourceSurface(RoundOut(transformBounds).Size(), SurfaceFormat::B8G8R8A8
#ifdef MOZ_ENABLE_SKIA
        , true
#endif
        );
    if (NS_WARN_IF(!temp)) {
      buffer->PopClip();
      return;
    }

    Transform(temp, source, new3DTransform, transformBounds.TopLeft());

    transformBounds.MoveTo(0, 0);
    buffer->DrawSurface(temp, transformBounds, transformBounds);
  }

  buffer->PopClip();
}
예제 #8
0
nsresult
imgFrame::InitWithDrawable(gfxDrawable* aDrawable,
                           const nsIntSize& aSize,
                           const SurfaceFormat aFormat,
                           Filter aFilter,
                           uint32_t aImageFlags)
{
  // Assert for properties that should be verified by decoders,
  // warn for properties related to bad content.
  if (!AllowedImageSize(aSize.width, aSize.height)) {
    NS_WARNING("Should have legal image size");
    mAborted = true;
    return NS_ERROR_FAILURE;
  }

  mImageSize = aSize;
  mOffset.MoveTo(0, 0);
  mSize.SizeTo(aSize.width, aSize.height);

  mFormat = aFormat;
  mPaletteDepth = 0;

  RefPtr<DrawTarget> target;

  bool canUseDataSurface =
    gfxPlatform::GetPlatform()->CanRenderContentToDataSurface();

  if (canUseDataSurface) {
    // It's safe to use data surfaces for content on this platform, so we can
    // get away with using volatile buffers.
    MOZ_ASSERT(!mImageSurface, "Called imgFrame::InitWithDrawable() twice?");

    mVBuf = AllocateBufferForImage(mSize, mFormat);
    if (!mVBuf) {
      mAborted = true;
      return NS_ERROR_OUT_OF_MEMORY;
    }

    int32_t stride = VolatileSurfaceStride(mSize, mFormat);
    VolatileBufferPtr<uint8_t> ptr(mVBuf);
    if (!ptr) {
      mAborted = true;
      return NS_ERROR_OUT_OF_MEMORY;
    }
    if (mVBuf->OnHeap()) {
      memset(ptr, 0, stride * mSize.height);
    }
    mImageSurface = CreateLockedSurface(mVBuf, mSize, mFormat);

    target = gfxPlatform::GetPlatform()->
      CreateDrawTargetForData(ptr, mSize, stride, mFormat);
  } else {
    // We can't use data surfaces for content, so we'll create an offscreen
    // surface instead.  This means if someone later calls RawAccessRef(), we
    // may have to do an expensive readback, but we warned callers about that in
    // the documentation for this method.
    MOZ_ASSERT(!mOptSurface, "Called imgFrame::InitWithDrawable() twice?");

    target = gfxPlatform::GetPlatform()->
      CreateOffscreenContentDrawTarget(mSize, mFormat);
  }

  if (!target) {
    mAborted = true;
    return NS_ERROR_OUT_OF_MEMORY;
  }

  // Draw using the drawable the caller provided.
  nsIntRect imageRect(0, 0, mSize.width, mSize.height);
  RefPtr<gfxContext> ctx = new gfxContext(target);
  gfxUtils::DrawPixelSnapped(ctx, aDrawable, mSize,
                             ImageRegion::Create(ThebesRect(imageRect)),
                             mFormat, aFilter, aImageFlags);

  if (canUseDataSurface && !mImageSurface) {
    NS_WARNING("Failed to create VolatileDataSourceSurface");
    mAborted = true;
    return NS_ERROR_OUT_OF_MEMORY;
  }

  if (!canUseDataSurface) {
    // We used an offscreen surface, which is an "optimized" surface from
    // imgFrame's perspective.
    mOptSurface = target->Snapshot();
  }

  // If we reach this point, we should regard ourselves as complete.
  mDecoded = GetRect();
  MOZ_ASSERT(IsImageComplete());

  return NS_OK;
}