CGContextRef gfxQuartzNativeDrawing::BeginNativeDrawing() { NS_ASSERTION(!mCGContext, "BeginNativeDrawing called when drawing already in progress"); if (mContext->IsCairo()) { // We're past that now. Any callers that still supply a Cairo context // don't deserve native theming. NS_WARNING("gfxQuartzNativeDrawing being used with a gfxContext that is not backed by a DrawTarget"); return nullptr; } DrawTarget *dt = mContext->GetDrawTarget(); if (dt->GetBackendType() != BackendType::COREGRAPHICS || dt->IsDualDrawTarget()) { IntSize backingSize(NSToIntFloor(mNativeRect.width * mBackingScale), NSToIntFloor(mNativeRect.height * mBackingScale)); if (backingSize.IsEmpty()) { return nullptr; } mDrawTarget = Factory::CreateDrawTarget(BackendType::COREGRAPHICS, backingSize, SurfaceFormat::B8G8R8A8); Matrix transform; transform.Scale(mBackingScale, mBackingScale); transform.Translate(-mNativeRect.x, -mNativeRect.y); mDrawTarget->SetTransform(transform); dt = mDrawTarget; } mCGContext = mBorrowedContext.Init(dt); MOZ_ASSERT(mCGContext); return mCGContext; }
void ClientLayerManager::MakeSnapshotIfRequired() { if (!mShadowTarget) { return; } if (mWidget) { if (CompositorChild* remoteRenderer = GetRemoteRenderer()) { nsIntRect bounds; mWidget->GetBounds(bounds); IntSize widgetSize = bounds.Size().ToIntSize(); SurfaceDescriptor inSnapshot, snapshot; if (mForwarder->AllocSurfaceDescriptor(widgetSize, gfxContentType::COLOR_ALPHA, &inSnapshot) && // The compositor will usually reuse |snapshot| and return // it through |outSnapshot|, but if it doesn't, it's // responsible for freeing |snapshot|. remoteRenderer->SendMakeSnapshot(inSnapshot, &snapshot)) { RefPtr<DataSourceSurface> surf = GetSurfaceForDescriptor(snapshot); DrawTarget* dt = mShadowTarget->GetDrawTarget(); Rect widgetRect(Point(0, 0), Size(widgetSize.width, widgetSize.height)); dt->DrawSurface(surf, widgetRect, widgetRect, DrawSurfaceOptions(), DrawOptions(1.0f, CompositionOp::OP_OVER)); } if (IsSurfaceDescriptorValid(snapshot)) { mForwarder->DestroySharedSurface(&snapshot); } } } mShadowTarget = nullptr; }
static void RepeatOrStretchSurface(DrawTarget& aDT, SourceSurface* aSurface, const Rect& aDest, const Rect& aSrc, Rect& aSkipRect) { if (aSkipRect.Contains(aDest)) { return; } if ((!aDT.GetTransform().IsRectilinear() && aDT.GetBackendType() != BackendType::CAIRO) || (aDT.GetBackendType() == BackendType::DIRECT2D)) { // Use stretching if possible, since it leads to less seams when the // destination is transformed. However, don't do this if we're using cairo, // because if cairo is using pixman it won't render anything for large // stretch factors because pixman's internal fixed point precision is not // high enough to handle those scale factors. // Calling FillRect on a D2D backend with a repeating pattern is much slower // than DrawSurface, so special case the D2D backend here. aDT.DrawSurface(aSurface, aDest, aSrc); return; } SurfacePattern pattern(aSurface, ExtendMode::REPEAT, Matrix::Translation(aDest.TopLeft() - aSrc.TopLeft()), Filter::GOOD, RoundedToInt(aSrc)); aDT.FillRect(aDest, pattern); }
void ClientLayerManager::MakeSnapshotIfRequired() { if (!mShadowTarget) { return; } if (mWidget) { if (CompositorChild* remoteRenderer = GetRemoteRenderer()) { nsIntRect bounds = ToOutsideIntRect(mShadowTarget->GetClipExtents()); SurfaceDescriptor inSnapshot; if (!bounds.IsEmpty() && mForwarder->AllocSurfaceDescriptor(bounds.Size().ToIntSize(), gfxContentType::COLOR_ALPHA, &inSnapshot) && remoteRenderer->SendMakeSnapshot(inSnapshot, bounds)) { RefPtr<DataSourceSurface> surf = GetSurfaceForDescriptor(inSnapshot); DrawTarget* dt = mShadowTarget->GetDrawTarget(); Rect dstRect(bounds.x, bounds.y, bounds.width, bounds.height); Rect srcRect(0, 0, bounds.width, bounds.height); dt->DrawSurface(surf, dstRect, srcRect, DrawSurfaceOptions(), DrawOptions(1.0f, CompositionOp::OP_OVER)); } mForwarder->DestroySharedSurface(&inSnapshot); } } mShadowTarget = nullptr; }
void nsCaret::PaintCaret(DrawTarget& aDrawTarget, nsIFrame* aForFrame, const nsPoint &aOffset) { int32_t contentOffset; nsIFrame* frame = GetFrameAndOffset(GetSelectionInternal(), mOverrideContent, mOverrideOffset, &contentOffset); if (!frame) { return; } NS_ASSERTION(frame == aForFrame, "We're referring different frame"); int32_t appUnitsPerDevPixel = frame->PresContext()->AppUnitsPerDevPixel(); nsRect caretRect; nsRect hookRect; ComputeCaretRects(frame, contentOffset, &caretRect, &hookRect); Rect devPxCaretRect = NSRectToSnappedRect(caretRect + aOffset, appUnitsPerDevPixel, aDrawTarget); Rect devPxHookRect = NSRectToSnappedRect(hookRect + aOffset, appUnitsPerDevPixel, aDrawTarget); ColorPattern color(ToDeviceColor(frame->GetCaretColorAt(contentOffset))); aDrawTarget.FillRect(devPxCaretRect, color); if (!hookRect.IsEmpty()) { aDrawTarget.FillRect(devPxHookRect, color); } }
already_AddRefed<Path> nsSVGPathGeometryElement::GetOrBuildPath(const DrawTarget& aDrawTarget, FillRule aFillRule) { // We only cache the path if it matches the backend used for screen painting: bool cacheable = aDrawTarget.GetBackendType() == gfxPlatform::GetPlatform()->GetDefaultContentBackend(); // Checking for and returning mCachedPath before checking the pref means // that the pref is only live on page reload (or app restart for SVG in // chrome). The benefit is that we avoid causing a CPU memory cache miss by // looking at the global variable that the pref's stored in. if (cacheable && mCachedPath) { if (aDrawTarget.GetBackendType() == mCachedPath->GetBackendType()) { RefPtr<Path> path(mCachedPath); return path.forget(); } } RefPtr<PathBuilder> builder = aDrawTarget.CreatePathBuilder(aFillRule); RefPtr<Path> path = BuildPath(builder); if (cacheable && NS_SVGPathCachingEnabled()) { mCachedPath = path; } return path.forget(); }
virtual void ProcessReadback(gfx::DataSourceSurface *aSourceSurface) { SourceRotatedBuffer rotBuffer(aSourceSurface, nullptr, mBufferRect, mBufferRotation); for (uint32_t i = 0; i < mReadbackUpdates.Length(); ++i) { ReadbackProcessor::Update& update = mReadbackUpdates[i]; nsIntPoint offset = update.mLayer->GetBackgroundLayerOffset(); ReadbackSink* sink = update.mLayer->GetSink(); if (!sink) { continue; } if (!aSourceSurface) { sink->SetUnknown(update.mSequenceCounter); continue; } nsRefPtr<gfxContext> ctx = sink->BeginUpdate(update.mUpdateRect + offset, update.mSequenceCounter); if (!ctx) { continue; } DrawTarget* dt = ctx->GetDrawTarget(); dt->SetTransform(Matrix::Translation(offset.x, offset.y)); rotBuffer.DrawBufferWithRotation(dt, RotatedBuffer::BUFFER_BLACK); update.mLayer->GetSink()->EndUpdate(ctx, update.mUpdateRect + offset); } }
void gfxQuartzNativeDrawing::EndNativeDrawing() { NS_ASSERTION(mCGContext, "EndNativeDrawing called without BeginNativeDrawing"); MOZ_ASSERT(!mContext->IsCairo(), "BeginNativeDrawing succeeded with cairo context?"); mBorrowedContext.Finish(); if (mDrawTarget) { DrawTarget *dest = mContext->GetDrawTarget(); RefPtr<SourceSurface> source = mDrawTarget->Snapshot(); IntSize backingSize(NSToIntFloor(mNativeRect.width * mBackingScale), NSToIntFloor(mNativeRect.height * mBackingScale)); Matrix oldTransform = dest->GetTransform(); Matrix newTransform = oldTransform; newTransform.Translate(mNativeRect.x, mNativeRect.y); newTransform.Scale(1.0f / mBackingScale, 1.0f / mBackingScale); dest->SetTransform(newTransform); dest->DrawSurface(source, gfx::Rect(0, 0, backingSize.width, backingSize.height), gfx::Rect(0, 0, backingSize.width, backingSize.height)); dest->SetTransform(oldTransform); } }
void StrokeSnappedEdgesOfRect(const Rect& aRect, DrawTarget& aDrawTarget, const ColorPattern& aColor, const StrokeOptions& aStrokeOptions) { if (aRect.IsEmpty()) { return; } Point p1 = aRect.TopLeft(); Point p2 = aRect.BottomLeft(); SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget); aDrawTarget.StrokeLine(p1, p2, aColor, aStrokeOptions); p1 = aRect.BottomLeft(); p2 = aRect.BottomRight(); SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget); aDrawTarget.StrokeLine(p1, p2, aColor, aStrokeOptions); p1 = aRect.TopLeft(); p2 = aRect.TopRight(); SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget); aDrawTarget.StrokeLine(p1, p2, aColor, aStrokeOptions); p1 = aRect.TopRight(); p2 = aRect.BottomRight(); SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget); aDrawTarget.StrokeLine(p1, p2, aColor, aStrokeOptions); }
/*** * Blur an inset box shadow by doing: * 1) Create a minimal box shadow path that creates a frame. * 2) Draw the box shadow portion over the destination surface. * 3) The "inset" part is created by a clip rect that properly clips * the alpha mask so that it has clean edges. We still create the full * proper alpha mask, but let the clip deal with the clean edges. * * All parameters should already be in device pixels. */ void gfxAlphaBoxBlur::BlurInsetBox(gfxContext* aDestinationCtx, const Rect aDestinationRect, const Rect aShadowClipRect, const gfxIntSize aBlurRadius, const gfxIntSize aSpreadRadius, const Color& aShadowColor, bool aHasBorderRadius, const RectCornerRadii& aInnerClipRadii, const Rect aSkipRect) { if ((aBlurRadius.width <= 0 && aBlurRadius.height <= 0)) { // The outer path must be rounded out // If not blurring, we're done now. Rect pathRect(aDestinationRect); pathRect.RoundOut(); FillDestinationPath(aDestinationCtx, pathRect, aShadowClipRect, aShadowColor, aHasBorderRadius, aInnerClipRadii); return; } DrawTarget* destDrawTarget = aDestinationCtx->GetDrawTarget(); Rect outerRect; Rect innerRect; Margin pathMargins; ComputeRectsForInsetBoxShadow(aBlurRadius, aSpreadRadius, aDestinationRect, aShadowClipRect, outerRect, innerRect, pathMargins); IntPoint topLeft; RefPtr<SourceSurface> minInsetBlur = GetInsetBlur(outerRect, innerRect, aBlurRadius, aSpreadRadius, aInnerClipRadii, aShadowColor, aHasBorderRadius, topLeft, aDestinationCtx); if (!minInsetBlur) { return; } Rect destRectOuter(aDestinationRect); destRectOuter.RoundIn(); Rect destRectInner(destRectOuter); destRectInner.Deflate(pathMargins); Rect srcRectOuter(outerRect); srcRectOuter.MoveBy(abs(topLeft.x), abs(topLeft.y)); Rect srcRectInner(srcRectOuter); srcRectInner.Deflate(pathMargins); if (srcRectOuter.IsEqualInterior(srcRectInner)) { destDrawTarget->DrawSurface(minInsetBlur, destRectOuter, srcRectOuter); } else { DrawBoxShadows(*destDrawTarget, minInsetBlur, destRectOuter, destRectInner, srcRectOuter, srcRectInner, aSkipRect); } }
void gfxContext::PushGroupAndCopyBackground(gfxContentType content) { IntRect clipExtents; if (mDT->GetFormat() != SurfaceFormat::B8G8R8X8) { gfxRect clipRect = GetRoundOutDeviceClipExtents(this); clipExtents = IntRect(clipRect.x, clipRect.y, clipRect.width, clipRect.height); } if ((mDT->GetFormat() == SurfaceFormat::B8G8R8X8 || mDT->GetOpaqueRect().Contains(clipExtents)) && !mDT->GetUserData(&sDontUseAsSourceKey)) { DrawTarget *oldDT = mDT; RefPtr<SourceSurface> source = mDT->Snapshot(); Point oldDeviceOffset = CurrentState().deviceOffset; PushNewDT(gfxContentType::COLOR); if (oldDT == mDT) { // Creating new DT failed. return; } Point offset = CurrentState().deviceOffset - oldDeviceOffset; Rect surfRect(0, 0, Float(mDT->GetSize().width), Float(mDT->GetSize().height)); Rect sourceRect = surfRect + offset; mDT->SetTransform(Matrix()); // XXX: It's really sad that we have to do this (for performance). // Once DrawTarget gets a PushLayer API we can implement this within // DrawTargetTiled. if (source->GetType() == SurfaceType::TILED) { SnapshotTiled *sourceTiled = static_cast<SnapshotTiled*>(source.get()); for (uint32_t i = 0; i < sourceTiled->mSnapshots.size(); i++) { Rect tileSourceRect = sourceRect.Intersect(Rect(sourceTiled->mOrigins[i].x, sourceTiled->mOrigins[i].y, sourceTiled->mSnapshots[i]->GetSize().width, sourceTiled->mSnapshots[i]->GetSize().height)); if (tileSourceRect.IsEmpty()) { continue; } Rect tileDestRect = tileSourceRect - offset; tileSourceRect -= sourceTiled->mOrigins[i]; mDT->DrawSurface(sourceTiled->mSnapshots[i], tileDestRect, tileSourceRect); } } else { mDT->DrawSurface(source, surfRect, sourceRect); } mDT->SetOpaqueRect(oldDT->GetOpaqueRect()); PushClipsToDT(mDT); mDT->SetTransform(GetDTTransform()); return; } PushGroup(content); }
DrawTarget* ContentClientIncremental::BorrowDrawTargetForPainting(const PaintState& aPaintState, RotatedContentBuffer::DrawIterator* aIter) { if (aPaintState.mMode == SurfaceMode::SURFACE_NONE) { return nullptr; } if (aIter) { if (aIter->mCount++ > 0) { return nullptr; } aIter->mDrawRegion = aPaintState.mRegionToDraw; } DrawTarget* result = nullptr; nsIntRect drawBounds = aPaintState.mRegionToDraw.GetBounds(); MOZ_ASSERT(!mLoanedDrawTarget); // BeginUpdate is allowed to modify the given region, // if it wants more to be repainted than we request. if (aPaintState.mMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) { nsIntRegion drawRegionCopy = aPaintState.mRegionToDraw; RefPtr<DrawTarget> onBlack = GetUpdateSurface(BUFFER_BLACK, drawRegionCopy); RefPtr<DrawTarget> onWhite = GetUpdateSurface(BUFFER_WHITE, aPaintState.mRegionToDraw); if (onBlack && onWhite) { NS_ASSERTION(aPaintState.mRegionToDraw == drawRegionCopy, "BeginUpdate should always modify the draw region in the same way!"); FillSurface(onBlack, aPaintState.mRegionToDraw, nsIntPoint(drawBounds.x, drawBounds.y), gfxRGBA(0.0, 0.0, 0.0, 1.0)); FillSurface(onWhite, aPaintState.mRegionToDraw, nsIntPoint(drawBounds.x, drawBounds.y), gfxRGBA(1.0, 1.0, 1.0, 1.0)); mLoanedDrawTarget = Factory::CreateDualDrawTarget(onBlack, onWhite); } else { mLoanedDrawTarget = nullptr; } } else { mLoanedDrawTarget = GetUpdateSurface(BUFFER_BLACK, aPaintState.mRegionToDraw); } if (!mLoanedDrawTarget) { NS_WARNING("unable to get context for update"); return nullptr; } result = mLoanedDrawTarget; mLoanedTransform = mLoanedDrawTarget->GetTransform(); mLoanedTransform.Translate(-drawBounds.x, -drawBounds.y); result->SetTransform(mLoanedTransform); mLoanedTransform.Translate(drawBounds.x, drawBounds.y); if (mContentType == gfxContentType::COLOR_ALPHA) { gfxUtils::ClipToRegion(result, aPaintState.mRegionToDraw); nsIntRect bounds = aPaintState.mRegionToDraw.GetBounds(); result->ClearRect(Rect(bounds.x, bounds.y, bounds.width, bounds.height)); } return result; }
static already_AddRefed<SourceSurface> GetBlur(gfxContext* aDestinationCtx, const IntSize& aRectSize, const IntSize& aBlurRadius, const RectCornerRadii* aCornerRadii, const Color& aShadowColor, bool aMirrorCorners, IntMargin& aOutBlurMargin, IntMargin& aOutSlice, IntSize& aOutMinSize) { if (!gBlurCache) { gBlurCache = new BlurCache(); } IntSize minSize = ComputeMinSizeForShadowShape(aCornerRadii, aBlurRadius, aOutSlice, aRectSize); // We can get seams using the min size rect when drawing to the destination rect // if we have a non-pixel aligned destination transformation. In those cases, // fallback to just rendering the destination rect. Matrix destMatrix = ToMatrix(aDestinationCtx->CurrentMatrix()); bool useDestRect = !destMatrix.IsRectilinear() || destMatrix.HasNonIntegerTranslation(); if (useDestRect) { minSize = aRectSize; } aOutMinSize = minSize; DrawTarget* destDT = aDestinationCtx->GetDrawTarget(); if (!useDestRect) { BlurCacheData* cached = gBlurCache->Lookup(minSize, aBlurRadius, aCornerRadii, aShadowColor, destDT->GetBackendType()); if (cached) { // See CreateBoxShadow() for these values aOutBlurMargin = cached->mBlurMargin; RefPtr<SourceSurface> blur = cached->mBlur; return blur.forget(); } } RefPtr<SourceSurface> boxShadow = CreateBoxShadow(destDT, minSize, aCornerRadii, aBlurRadius, aShadowColor, aMirrorCorners, aOutBlurMargin); if (!boxShadow) { return nullptr; } if (!useDestRect) { CacheBlur(destDT, minSize, aBlurRadius, aCornerRadii, aShadowColor, aOutBlurMargin, boxShadow); } return boxShadow.forget(); }
/*** * Blur an inset box shadow by doing: * 1) Create a minimal box shadow path that creates a frame. * 2) Draw the box shadow portion over the destination surface. * 3) The "inset" part is created by a clip rect that properly clips * the alpha mask so that it has clean edges. We still create the full * proper alpha mask, but let the clip deal with the clean edges. * * All parameters should already be in device pixels. */ void gfxAlphaBoxBlur::BlurInsetBox(gfxContext* aDestinationCtx, const Rect aDestinationRect, const Rect aShadowClipRect, const IntSize aBlurRadius, const IntSize aSpreadRadius, const Color& aShadowColor, bool aHasBorderRadius, const RectCornerRadii& aInnerClipRadii, const Rect aSkipRect, const Point aShadowOffset) { DrawTarget* destDrawTarget = aDestinationCtx->GetDrawTarget(); // Blur inset shadows ALWAYS have a 0 spread radius. if ((aBlurRadius.width <= 0 && aBlurRadius.height <= 0)) { FillDestinationPath(aDestinationCtx, aDestinationRect, aShadowClipRect, aShadowColor, aHasBorderRadius, aInnerClipRadii); return; } IntMargin extendDest; IntMargin slice; bool didMoveOffset; RefPtr<SourceSurface> minInsetBlur = GetInsetBlur(extendDest, slice, aDestinationRect, aShadowClipRect, aBlurRadius, aSpreadRadius, aInnerClipRadii, aShadowColor, aHasBorderRadius, aShadowOffset, didMoveOffset, destDrawTarget); if (!minInsetBlur) { return; } Rect srcOuter(Point(), Size(minInsetBlur->GetSize())); Rect srcInner = srcOuter; srcInner.Deflate(Margin(slice)); Rect dstOuter(aDestinationRect); if (!didMoveOffset) { dstOuter.MoveBy(aShadowOffset); } dstOuter.Inflate(Margin(extendDest)); Rect dstInner = dstOuter; dstInner.Deflate(Margin(slice)); if (dstOuter.Size() == srcOuter.Size()) { destDrawTarget->DrawSurface(minInsetBlur, dstOuter, srcOuter); } else { DrawBoxShadows(*destDrawTarget, minInsetBlur, dstOuter, dstInner, srcOuter, srcInner, aSkipRect); } }
void ClientLayerManager::MakeSnapshotIfRequired() { if (!mShadowTarget) { return; } if (mWidget) { if (CompositorBridgeChild* remoteRenderer = GetRemoteRenderer()) { // The compositor doesn't draw to a different sized surface // when there's a rotation. Instead we rotate the result // when drawing into dt LayoutDeviceIntRect outerBounds; mWidget->GetBounds(outerBounds); IntRect bounds = ToOutsideIntRect(mShadowTarget->GetClipExtents()); if (mTargetRotation) { bounds = RotateRect(bounds, outerBounds.ToUnknownRect(), mTargetRotation); } SurfaceDescriptor inSnapshot; if (!bounds.IsEmpty() && mForwarder->AllocSurfaceDescriptor(bounds.Size(), gfxContentType::COLOR_ALPHA, &inSnapshot)) { // Make a copy of |inSnapshot| because the call to send it over IPC // will call forget() on the Shmem inside, and zero it out. SurfaceDescriptor outSnapshot = inSnapshot; if (remoteRenderer->SendMakeSnapshot(inSnapshot, bounds)) { RefPtr<DataSourceSurface> surf = GetSurfaceForDescriptor(outSnapshot); DrawTarget* dt = mShadowTarget->GetDrawTarget(); Rect dstRect(bounds.x, bounds.y, bounds.width, bounds.height); Rect srcRect(0, 0, bounds.width, bounds.height); gfx::Matrix rotate = ComputeTransformForUnRotation(outerBounds.ToUnknownRect(), mTargetRotation); gfx::Matrix oldMatrix = dt->GetTransform(); dt->SetTransform(rotate * oldMatrix); dt->DrawSurface(surf, dstRect, srcRect, DrawSurfaceOptions(), DrawOptions(1.0f, CompositionOp::OP_OVER)); dt->SetTransform(oldMatrix); } mForwarder->DestroySurfaceDescriptor(&outSnapshot); } } } mShadowTarget = nullptr; }
void GradientStopsView::UpdateView() { DrawTarget *dt = ui->dtWidget->GetDT(); dt->FillRect(Rect(0, 0, 100000, 100000), ColorPattern(Color(0.5f, 0.5f, 0.5f, 1.0f))); RefPtr<GradientStops> stops = mTranslator->LookupGradientStops(mRefPtr); ui->listWidget->clear(); if (!stops) { dt->Flush(); ui->dtWidget->redraw(); ui->listWidget->addItem("Dead"); return; } IntSize dstSize = dt->GetSize(); RefPtr<DrawTarget> tmpdt = dt->CreateSimilarDrawTarget(IntSize(20, 20), SurfaceFormat::B8G8R8X8); tmpdt->FillRect(Rect(0, 0, 10, 10), ColorPattern(Color(1.0f, 1.0f, 1.0f))); tmpdt->FillRect(Rect(10, 10, 10, 10), ColorPattern(Color(1.0f, 1.0f, 1.0f))); tmpdt->FillRect(Rect(10, 0, 10, 10), ColorPattern(Color(0.7f, 0.7f, 0.7f))); tmpdt->FillRect(Rect(0, 10, 10, 10), ColorPattern(Color(0.7f, 0.7f, 0.7f))); RefPtr<SourceSurface> src = tmpdt->Snapshot(); tmpdt = NULL; Rect dstRect(0, 0, dstSize.width, dstSize.height); dt->FillRect(dstRect, SurfacePattern(src, ExtendMode::REPEAT)); dt->FillRect(dstRect, LinearGradientPattern(Point(0, dstSize.height / 2), Point(dstSize.width, dstSize.height / 2), stops)); dt->Flush(); ui->dtWidget->redraw(); }
void nsDisplayCanvasBackgroundColor::Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) { nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame); nsPoint offset = ToReferenceFrame(); nsRect bgClipRect = frame->CanvasArea() + offset; if (NS_GET_A(mColor) > 0) { DrawTarget* drawTarget = aCtx->GetDrawTarget(); int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel(); Rect devPxRect = NSRectToSnappedRect(bgClipRect, appUnitsPerDevPixel, *drawTarget); drawTarget->FillRect(devPxRect, ColorPattern(ToDeviceColor(mColor))); } }
already_AddRefed<Path> ScaledFontBase::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget) { #ifdef USE_SKIA if (aTarget->GetBackendType() == BackendType::SKIA) { SkPath path = GetSkiaPathForGlyphs(aBuffer); return MakeAndAddRef<PathSkia>(path, FillRule::FILL_WINDING); } #endif #ifdef USE_CAIRO if (aTarget->GetBackendType() == BackendType::CAIRO) { MOZ_ASSERT(mScaledFont); DrawTarget *dt = const_cast<DrawTarget*>(aTarget); cairo_t *ctx = static_cast<cairo_t*>(dt->GetNativeSurface(NativeSurfaceType::CAIRO_CONTEXT)); bool isNewContext = !ctx; if (!ctx) { ctx = cairo_create(DrawTargetCairo::GetDummySurface()); cairo_matrix_t mat; GfxMatrixToCairoMatrix(aTarget->GetTransform(), mat); cairo_set_matrix(ctx, &mat); } cairo_set_scaled_font(ctx, mScaledFont); // Convert our GlyphBuffer into an array of Cairo glyphs. std::vector<cairo_glyph_t> glyphs(aBuffer.mNumGlyphs); for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) { glyphs[i].index = aBuffer.mGlyphs[i].mIndex; glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x; glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y; } cairo_new_path(ctx); cairo_glyph_path(ctx, &glyphs[0], aBuffer.mNumGlyphs); RefPtr<PathCairo> newPath = new PathCairo(ctx); if (isNewContext) { cairo_destroy(ctx); } return newPath.forget(); } #endif return nullptr; }
bool SnapLineToDevicePixelsForStroking(Point& aP1, Point& aP2, const DrawTarget& aDrawTarget) { Matrix mat = aDrawTarget.GetTransform(); if (mat.HasNonTranslation()) { return false; } if (aP1.x != aP2.x && aP1.y != aP2.y) { return false; // not a horizontal or vertical line } Point p1 = aP1 + mat.GetTranslation(); // into device space Point p2 = aP2 + mat.GetTranslation(); p1.Round(); p2.Round(); p1 -= mat.GetTranslation(); // back into user space p2 -= mat.GetTranslation(); if (aP1.x == aP2.x) { // snap vertical line, adding 0.5 to align it to be mid-pixel: aP1 = p1 + Point(0.5, 0); aP2 = p2 + Point(0.5, 0); } else { // snap horizontal line, adding 0.5 to align it to be mid-pixel: aP1 = p1 + Point(0, 0.5); aP2 = p2 + Point(0, 0.5); } return true; }
// Blurs a small surface and creates the mask. static already_AddRefed<SourceSurface> CreateBlurMask(const IntSize& aRectSize, RectCornerRadii* aCornerRadii, gfxIntSize aBlurRadius, IntMargin& aExtendDestBy, IntMargin& aSliceBorder, DrawTarget& aDestDrawTarget) { IntMargin slice; gfxAlphaBoxBlur blur; IntSize minSize = ComputeMinSizeForShadowShape(aCornerRadii, aBlurRadius, slice, aRectSize); IntRect minRect(IntPoint(), minSize); gfxContext* blurCtx = blur.Init(ThebesRect(Rect(minRect)), gfxIntSize(), aBlurRadius, nullptr, nullptr); if (!blurCtx) { return nullptr; } DrawTarget* blurDT = blurCtx->GetDrawTarget(); ColorPattern black(Color(0.f, 0.f, 0.f, 1.f)); if (aCornerRadii) { RefPtr<Path> roundedRect = MakePathForRoundedRect(*blurDT, Rect(minRect), *aCornerRadii); blurDT->Fill(roundedRect, black); } else { blurDT->FillRect(Rect(minRect), black); } IntPoint topLeft; RefPtr<SourceSurface> result = blur.DoBlur(&aDestDrawTarget, &topLeft); if (!result) { return nullptr; } IntRect expandedMinRect(topLeft, result->GetSize()); aExtendDestBy = expandedMinRect - minRect; aSliceBorder = slice + aExtendDestBy; MOZ_ASSERT(aSliceBorder.LeftRight() <= expandedMinRect.width); MOZ_ASSERT(aSliceBorder.TopBottom() <= expandedMinRect.height); return result.forget(); }
void nsDisplayCanvasBackgroundImage::Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) { nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame); nsPoint offset = ToReferenceFrame(); nsRect bgClipRect = frame->CanvasArea() + offset; nsRenderingContext context; nsRefPtr<gfxContext> dest = aCtx->ThebesContext(); RefPtr<DrawTarget> dt; gfxRect destRect; #ifndef MOZ_GFX_OPTIMIZE_MOBILE if (IsSingleFixedPositionImage(aBuilder, bgClipRect, &destRect) && aBuilder->IsPaintingToWindow() && !aBuilder->IsCompositingCheap() && !dest->CurrentMatrix().HasNonIntegerTranslation()) { // Snap image rectangle to nearest pixel boundaries. This is the right way // to snap for this context, because we checked HasNonIntegerTranslation above. destRect.Round(); dt = static_cast<DrawTarget*>(Frame()->Properties().Get(nsIFrame::CachedBackgroundImageDT())); DrawTarget* destDT = dest->GetDrawTarget(); if (dt) { BlitSurface(destDT, destRect, dt); return; } dt = destDT->CreateSimilarDrawTarget(IntSize(ceil(destRect.width), ceil(destRect.height)), SurfaceFormat::B8G8R8A8); if (dt) { nsRefPtr<gfxContext> ctx = new gfxContext(dt); ctx->SetMatrix( ctx->CurrentMatrix().Translate(-destRect.x, -destRect.y)); context.Init(ctx); } } #endif PaintInternal(aBuilder, dt ? &context : aCtx, dt ? bgClipRect: mVisibleRect, &bgClipRect); if (dt) { BlitSurface(dest->GetDrawTarget(), destRect, dt); frame->Properties().Set(nsIFrame::CachedBackgroundImageDT(), dt.forget().take()); } }
void DrawBlur(gfxContext* aDestinationCtx, SourceSurface* aBlur, const IntPoint& aTopLeft, const Rect* aDirtyRect) { DrawTarget *dest = aDestinationCtx->GetDrawTarget(); nsRefPtr<gfxPattern> thebesPat = aDestinationCtx->GetPattern(); Pattern* pat = thebesPat->GetPattern(dest, nullptr); Matrix oldTransform = dest->GetTransform(); Matrix newTransform = oldTransform; newTransform.Translate(aTopLeft.x, aTopLeft.y); // Avoid a semi-expensive clip operation if we can, otherwise // clip to the dirty rect if (aDirtyRect) { dest->PushClipRect(*aDirtyRect); } dest->SetTransform(newTransform); dest->MaskSurface(*pat, aBlur, Point(0, 0)); dest->SetTransform(oldTransform); if (aDirtyRect) { dest->PopClip(); } }
void ClientLayerManager::MakeSnapshotIfRequired() { if (!mShadowTarget) { return; } if (mWidget) { if (CompositorChild* remoteRenderer = GetRemoteRenderer()) { // The compositor doesn't draw to a different sized surface // when there's a rotation. Instead we rotate the result // when drawing into dt nsIntRect outerBounds; mWidget->GetBounds(outerBounds); nsIntRect bounds = ToOutsideIntRect(mShadowTarget->GetClipExtents()); if (mTargetRotation) { bounds = RotateRect(bounds, outerBounds, mTargetRotation); } SurfaceDescriptor inSnapshot; if (!bounds.IsEmpty() && mForwarder->AllocSurfaceDescriptor(bounds.Size().ToIntSize(), gfxContentType::COLOR_ALPHA, &inSnapshot) && remoteRenderer->SendMakeSnapshot(inSnapshot, bounds)) { RefPtr<DataSourceSurface> surf = GetSurfaceForDescriptor(inSnapshot); DrawTarget* dt = mShadowTarget->GetDrawTarget(); Rect dstRect(bounds.x, bounds.y, bounds.width, bounds.height); Rect srcRect(0, 0, bounds.width, bounds.height); gfx::Matrix rotate = ComputeTransformForUnRotation(outerBounds, mTargetRotation); gfx::Matrix oldMatrix = dt->GetTransform(); dt->SetTransform(oldMatrix * rotate); dt->DrawSurface(surf, dstRect, srcRect, DrawSurfaceOptions(), DrawOptions(1.0f, CompositionOp::OP_OVER)); dt->SetTransform(oldMatrix); } mForwarder->DestroySharedSurface(&inSnapshot); } } mShadowTarget = nullptr; }
TextureClient* CairoImage::GetTextureClient(CompositableClient *aClient) { if (!aClient) { return nullptr; } CompositableForwarder* forwarder = aClient->GetForwarder(); RefPtr<TextureClient> textureClient = mTextureClients.Get(forwarder->GetSerial()); if (textureClient) { return textureClient; } RefPtr<SourceSurface> surface = GetAsSourceSurface(); MOZ_ASSERT(surface); if (!surface) { return nullptr; } // gfx::BackendType::NONE means default to content backend textureClient = aClient->CreateTextureClientForDrawing(surface->GetFormat(), surface->GetSize(), gfx::BackendType::NONE, TextureFlags::DEFAULT); if (!textureClient) { return nullptr; } MOZ_ASSERT(textureClient->CanExposeDrawTarget()); if (!textureClient->Lock(OpenMode::OPEN_WRITE_ONLY)) { return nullptr; } TextureClientAutoUnlock autoUnolck(textureClient); { // We must not keep a reference to the DrawTarget after it has been unlocked. DrawTarget* dt = textureClient->BorrowDrawTarget(); if (!dt) { return nullptr; } dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint()); } mTextureClients.Put(forwarder->GetSerial(), textureClient); return textureClient; }
CGContextRef gfxQuartzNativeDrawing::BeginNativeDrawing() { NS_ASSERTION(!mCGContext, "BeginNativeDrawing called when drawing already in progress"); DrawTarget *dt = mDrawTarget; if (dt->IsDualDrawTarget() || dt->IsTiledDrawTarget() || dt->GetBackendType() != BackendType::SKIA || dt->IsRecording()) { // We need a DrawTarget that we can get a CGContextRef from: Matrix transform = dt->GetTransform(); mNativeRect = transform.TransformBounds(mNativeRect); mNativeRect.RoundOut(); if (mNativeRect.IsEmpty()) { return nullptr; } mTempDrawTarget = Factory::CreateDrawTarget(BackendType::SKIA, IntSize::Truncate(mNativeRect.width, mNativeRect.height), SurfaceFormat::B8G8R8A8); if (!mTempDrawTarget) { return nullptr; } transform.PostTranslate(-mNativeRect.x, -mNativeRect.y); mTempDrawTarget->SetTransform(transform); dt = mTempDrawTarget; } else { // Clip the DT in case BorrowedCGContext needs to create a new layer. // This prevents it from creating a new layer the size of the window. // But make sure that this clip is device pixel aligned. Matrix transform = dt->GetTransform(); Rect deviceRect = transform.TransformBounds(mNativeRect); deviceRect.RoundOut(); mNativeRect = transform.Inverse().TransformBounds(deviceRect); mDrawTarget->PushClipRect(mNativeRect); } MOZ_ASSERT(dt->GetBackendType() == BackendType::SKIA); mCGContext = mBorrowedContext.Init(dt); if (NS_WARN_IF(!mCGContext)) { // Failed borrowing CG context, so we need to clean up. if (!mTempDrawTarget) { mDrawTarget->PopClip(); } return nullptr; } return mCGContext; }
static void PaintIndeterminateMark(nsIFrame* aFrame, nsRenderingContext* aCtx, const nsRect& aDirtyRect, nsPoint aPt) { DrawTarget* drawTarget = aCtx->GetDrawTarget(); int32_t appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel(); nsRect rect(aPt, aFrame->GetSize()); rect.Deflate(aFrame->GetUsedBorderAndPadding()); rect.y += (rect.height - rect.height/4) / 2; rect.height /= 4; Rect devPxRect = NSRectToSnappedRect(rect, appUnitsPerDevPixel, *drawTarget); drawTarget->FillRect(devPxRect, ColorPattern(ToDeviceColor(aFrame->StyleColor()->mColor))); }
void gfxQuartzNativeDrawing::EndNativeDrawing() { NS_ASSERTION(mCGContext, "EndNativeDrawing called without BeginNativeDrawing"); if (mBorrowedContext.cg) { MOZ_ASSERT(!mContext->IsCairo()); mBorrowedContext.Finish(); if (mDrawTarget) { DrawTarget *dest = mContext->GetDrawTarget(); RefPtr<SourceSurface> source = mDrawTarget->Snapshot(); IntSize backingSize(NSToIntFloor(mNativeRect.width * mBackingScale), NSToIntFloor(mNativeRect.height * mBackingScale)); Matrix oldTransform = dest->GetTransform(); Matrix newTransform = oldTransform; newTransform.Translate(mNativeRect.x, mNativeRect.y); newTransform.Scale(1.0f / mBackingScale, 1.0f / mBackingScale); dest->SetTransform(newTransform); dest->DrawSurface(source, gfx::Rect(0, 0, backingSize.width, backingSize.height), gfx::Rect(0, 0, backingSize.width, backingSize.height)); dest->SetTransform(oldTransform); } return; } cairo_quartz_finish_cg_context_with_clip(mSurfaceContext->GetCairo()); mQuartzSurface->MarkDirty(); if (mSurfaceContext != mContext) { gfxContextMatrixAutoSaveRestore save(mContext); // Copy back to destination mContext->Translate(mNativeRect.TopLeft()); mContext->Scale(1.0f / mBackingScale, 1.0f / mBackingScale); mContext->DrawSurface(mQuartzSurface, mQuartzSurface->GetSize()); } }
static void DrawCorner(DrawTarget& aDT, SourceSurface* aSurface, const Rect& aDest, const Rect& aSrc, Rect& aSkipRect) { if (aSkipRect.Contains(aDest)) { return; } aDT.DrawSurface(aSurface, aDest, aSrc); }
void PaintThread::PaintContentsAsync(CompositorBridgeChild* aBridge, CapturedPaintState* aState, PrepDrawTargetForPaintingCallback aCallback) { MOZ_ASSERT(IsOnPaintThread()); MOZ_ASSERT(aState); DrawTarget* target = aState->mTarget; DrawTargetCapture* capture = aState->mCapture; AutoCapturedPaintSetup setup(aState, aBridge); if (!aCallback(aState)) { return; } // Draw all the things into the actual dest target. target->DrawCapturedDT(capture, Matrix()); }
static void PaintDebugPlaceholder(nsIFrame* aFrame, nsRenderingContext* aCtx, const nsRect& aDirtyRect, nsPoint aPt) { ColorPattern cyan(ToDeviceColor(Color(0.f, 1.f, 1.f, 1.f))); DrawTarget* drawTarget = aCtx->GetDrawTarget(); int32_t appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel(); nscoord x = nsPresContext::CSSPixelsToAppUnits(-5); nsRect r(aPt.x + x, aPt.y, nsPresContext::CSSPixelsToAppUnits(13), nsPresContext::CSSPixelsToAppUnits(3)); drawTarget->FillRect(NSRectToRect(r, appUnitsPerDevPixel), cyan); nscoord y = nsPresContext::CSSPixelsToAppUnits(-10); r = nsRect(aPt.x, aPt.y + y, nsPresContext::CSSPixelsToAppUnits(3), nsPresContext::CSSPixelsToAppUnits(10)); drawTarget->FillRect(NSRectToRect(r, appUnitsPerDevPixel), cyan); }