void nsRenderingContext::FillEllipse(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) { mThebes->NewPath(); mThebes->Ellipse(gfxPoint(FROM_TWIPS(aX) + FROM_TWIPS(aWidth)/2.0, FROM_TWIPS(aY) + FROM_TWIPS(aHeight)/2.0), gfxSize(FROM_TWIPS(aWidth), FROM_TWIPS(aHeight))); mThebes->Fill(); }
SurfaceFormat UploadSurfaceToTexture(GLContext* gl, gfxASurface *aSurface, const nsIntRegion& aDstRegion, GLuint& aTexture, bool aOverwrite, const nsIntPoint& aSrcPoint, bool aPixelBuffer, GLenum aTextureUnit, GLenum aTextureTarget) { nsRefPtr<gfxImageSurface> imageSurface = aSurface->GetAsImageSurface(); unsigned char* data = nullptr; if (!imageSurface || (imageSurface->Format() != gfxImageFormatARGB32 && imageSurface->Format() != gfxImageFormatRGB24 && imageSurface->Format() != gfxImageFormatRGB16_565 && imageSurface->Format() != gfxImageFormatA8)) { // We can't get suitable pixel data for the surface, make a copy nsIntRect bounds = aDstRegion.GetBounds(); imageSurface = new gfxImageSurface(gfxIntSize(bounds.width, bounds.height), gfxImageFormatARGB32); nsRefPtr<gfxContext> context = new gfxContext(imageSurface); context->Translate(-gfxPoint(aSrcPoint.x, aSrcPoint.y)); context->SetSource(aSurface); context->Paint(); data = imageSurface->Data(); NS_ASSERTION(!aPixelBuffer, "Must be using an image compatible surface with pixel buffers!"); } else { // If a pixel buffer is bound the data pointer parameter is relative // to the start of the data block. if (!aPixelBuffer) { data = imageSurface->Data(); } data += DataOffset(aSrcPoint, imageSurface->Stride(), imageSurface->Format()); } MOZ_ASSERT(imageSurface); imageSurface->Flush(); return UploadImageDataToTexture(gl, data, imageSurface->Stride(), imageSurface->Format(), aDstRegion, aTexture, aOverwrite, aPixelBuffer, aTextureUnit, aTextureTarget); }
bool gfxContext::UserToDevicePixelSnapped(gfxRect& rect, bool ignoreScale) const { if (GetFlags() & FLAG_DISABLE_SNAPPING) return PR_FALSE; // if we're not at 1.0 scale, don't snap, unless we're // ignoring the scale. If we're not -just- a scale, // never snap. const gfxFloat epsilon = 0.0000001; #define WITHIN_E(a,b) (fabs((a)-(b)) < epsilon) cairo_matrix_t mat; cairo_get_matrix(mCairo, &mat); if (!ignoreScale && (!WITHIN_E(mat.xx,1.0) || !WITHIN_E(mat.yy,1.0) || !WITHIN_E(mat.xy,0.0) || !WITHIN_E(mat.yx,0.0))) return PR_FALSE; #undef WITHIN_E gfxPoint p1 = UserToDevice(rect.TopLeft()); gfxPoint p2 = UserToDevice(rect.TopRight()); gfxPoint p3 = UserToDevice(rect.BottomRight()); // Check that the rectangle is axis-aligned. For an axis-aligned rectangle, // two opposite corners define the entire rectangle. So check if // the axis-aligned rectangle with opposite corners p1 and p3 // define an axis-aligned rectangle whose other corners are p2 and p4. // We actually only need to check one of p2 and p4, since an affine // transform maps parallelograms to parallelograms. if (p2 == gfxPoint(p1.x, p3.y) || p2 == gfxPoint(p3.x, p1.y)) { p1.Round(); p3.Round(); rect.MoveTo(gfxPoint(NS_MIN(p1.x, p3.x), NS_MIN(p1.y, p3.y))); rect.SizeTo(gfxSize(NS_MAX(p1.x, p3.x) - rect.X(), NS_MAX(p1.y, p3.y) - rect.Y())); return PR_TRUE; } return PR_FALSE; }
nsresult SVGFEImageElement::Filter(nsSVGFilterInstance *instance, const nsTArray<const Image*>& aSources, const Image* aTarget, const nsIntRect& rect) { nsIFrame* frame = GetPrimaryFrame(); if (!frame) return NS_ERROR_FAILURE; nsCOMPtr<imgIRequest> currentRequest; GetRequest(nsIImageLoadingContent::CURRENT_REQUEST, getter_AddRefs(currentRequest)); nsCOMPtr<imgIContainer> imageContainer; if (currentRequest) currentRequest->GetImage(getter_AddRefs(imageContainer)); nsRefPtr<gfxASurface> currentFrame; if (imageContainer) imageContainer->GetFrame(imgIContainer::FRAME_CURRENT, imgIContainer::FLAG_SYNC_DECODE, getter_AddRefs(currentFrame)); // We need to wrap the surface in a pattern to have somewhere to set the // graphics filter. nsRefPtr<gfxPattern> thebesPattern; if (currentFrame) thebesPattern = new gfxPattern(currentFrame); if (thebesPattern) { thebesPattern->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(frame)); int32_t nativeWidth, nativeHeight; imageContainer->GetWidth(&nativeWidth); imageContainer->GetHeight(&nativeHeight); const gfxRect& filterSubregion = aTarget->mFilterPrimitiveSubregion; gfxMatrix viewBoxTM = SVGContentUtils::GetViewBoxTransform(filterSubregion.Width(), filterSubregion.Height(), 0,0, nativeWidth, nativeHeight, mPreserveAspectRatio); gfxMatrix xyTM = gfxMatrix().Translate(gfxPoint(filterSubregion.X(), filterSubregion.Y())); gfxMatrix TM = viewBoxTM * xyTM; nsRefPtr<gfxContext> ctx = new gfxContext(aTarget->mImage); nsSVGUtils::CompositePatternMatrix(ctx, thebesPattern, TM, nativeWidth, nativeHeight, 1.0); } return NS_OK; }
static gfxMatrix DeviceToImageTransform(gfxContext* aContext, const gfxMatrix& aUserSpaceToImageSpace) { gfxFloat deviceX, deviceY; nsRefPtr<gfxASurface> currentTarget = aContext->CurrentSurface(&deviceX, &deviceY); gfxMatrix currentMatrix = aContext->CurrentMatrix(); gfxMatrix deviceToUser = gfxMatrix(currentMatrix).Invert(); deviceToUser.Translate(-gfxPoint(-deviceX, -deviceY)); return gfxMatrix(deviceToUser).Multiply(aUserSpaceToImageSpace); }
void gfxContext::DrawSurface(gfxASurface *surface, gfxSize size) { cairo_save(mCairo); cairo_set_source_surface(mCairo, surface->CairoSurface(), 0, 0); cairo_new_path(mCairo); // pixel-snap this Rectangle(gfxRect(gfxPoint(0.0, 0.0), size), PR_TRUE); cairo_fill(mCairo); cairo_restore(mCairo); }
nsresult imgFrame::Extract(const nsIntRect& aRegion, imgFrame** aResult) { nsAutoPtr<imgFrame> subImage(new imgFrame()); if (!subImage) return NS_ERROR_OUT_OF_MEMORY; // The scaling problems described in bug 468496 are especially // likely to be visible for the sub-image, as at present the only // user is the border-image code and border-images tend to get // stretched a lot. At the same time, the performance concerns // that prevent us from just using Cairo's fallback scaler when // accelerated graphics won't cut it are less relevant to such // images, since they also tend to be small. Thus, we forcibly // disable the use of anything other than a client-side image // surface for the sub-image; this ensures that the correct // (albeit slower) Cairo fallback scaler will be used. subImage->mNeverUseDeviceSurface = PR_TRUE; nsresult rv = subImage->Init(0, 0, aRegion.width, aRegion.height, mFormat, mPaletteDepth); NS_ENSURE_SUCCESS(rv, rv); // scope to destroy ctx { gfxContext ctx(subImage->ThebesSurface()); ctx.SetOperator(gfxContext::OPERATOR_SOURCE); if (mSinglePixel) { ctx.SetDeviceColor(mSinglePixelColor); } else { // SetSource() places point (0,0) of its first argument at // the coordinages given by its second argument. We want // (x,y) of the image to be (0,0) of source space, so we // put (0,0) of the image at (-x,-y). ctx.SetSource(this->ThebesSurface(), gfxPoint(-aRegion.x, -aRegion.y)); } ctx.Rectangle(gfxRect(0, 0, aRegion.width, aRegion.height)); ctx.Fill(); } nsIntRect filled(0, 0, aRegion.width, aRegion.height); rv = subImage->ImageUpdated(filled); NS_ENSURE_SUCCESS(rv, rv); subImage->Optimize(); *aResult = subImage.forget(); return NS_OK; }
already_AddRefed<gfxImageSurface> nsSVGFilterInstance::CreateImage() { nsRefPtr<gfxImageSurface> surface = new gfxImageSurface(gfxIntSize(mSurfaceRect.width, mSurfaceRect.height), gfxASurface::ImageFormatARGB32); if (!surface || surface->CairoStatus()) return nullptr; surface->SetDeviceOffset(gfxPoint(-mSurfaceRect.x, -mSurfaceRect.y)); return surface.forget(); }
// For 'by'. bool SVGMotionSMILPathUtils::PathGenerator:: LineToRelative(const nsAString& aCoordPairStr, double& aSegmentDistance) { mHaveReceivedCommands = true; float xVal, yVal; if (!ParseCoordinatePair(aCoordPairStr, xVal, yVal)) { return false; } mGfxContext.LineTo(mGfxContext.CurrentPoint() + gfxPoint(xVal, yVal)); aSegmentDistance = NS_hypot(xVal, yVal); return true; }
NS_IMETHODIMP nsThebesRenderingContext::FillEllipse(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) { PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::FillEllipse [%d,%d,%d,%d]\n", this, aX, aY, aWidth, aHeight)); mThebes->NewPath(); mThebes->Ellipse(gfxPoint(FROM_TWIPS(aX) + FROM_TWIPS(aWidth)/2.0, FROM_TWIPS(aY) + FROM_TWIPS(aHeight)/2.0), gfxSize(FROM_TWIPS(aWidth), FROM_TWIPS(aHeight))); mThebes->Fill(); return NS_OK; }
nsSVGPathGeometryFrame::GetFrameForPoint(const nsPoint &aPoint) { PRUint16 fillRule, hitTestFlags; if (GetStateBits() & NS_STATE_SVG_CLIPPATH_CHILD) { hitTestFlags = SVG_HIT_TEST_FILL; fillRule = GetClipRule(); } else { hitTestFlags = GetHitTestFlags(); // XXX once bug 614732 is fixed, aPoint won't need any conversion in order // to compare it with mRect. gfxMatrix canvasTM = GetCanvasTM(); if (canvasTM.IsSingular()) { return nsnull; } nsPoint point = nsSVGUtils::TransformOuterSVGPointToChildFrame(aPoint, canvasTM, PresContext()); if (!hitTestFlags || ((hitTestFlags & SVG_HIT_TEST_CHECK_MRECT) && !mRect.Contains(point))) return nsnull; fillRule = GetStyleSVG()->mFillRule; } bool isHit = false; nsRefPtr<gfxContext> context = new gfxContext(gfxPlatform::GetPlatform()->ScreenReferenceSurface()); GeneratePath(context); gfxPoint userSpacePoint = context->DeviceToUser(gfxPoint(PresContext()->AppUnitsToGfxUnits(aPoint.x), PresContext()->AppUnitsToGfxUnits(aPoint.y))); if (fillRule == NS_STYLE_FILL_RULE_EVENODD) context->SetFillRule(gfxContext::FILL_RULE_EVEN_ODD); else context->SetFillRule(gfxContext::FILL_RULE_WINDING); if (hitTestFlags & SVG_HIT_TEST_FILL) isHit = context->PointInFill(userSpacePoint); if (!isHit && (hitTestFlags & SVG_HIT_TEST_STROKE)) { SetupCairoStrokeHitGeometry(context); isHit = context->PointInStroke(userSpacePoint); } if (isHit && nsSVGUtils::HitTestClip(this, aPoint)) return this; return nsnull; }
// For 'from' and the first entry in 'values'. bool SVGMotionSMILPathUtils::PathGenerator:: MoveToAbsolute(const nsAString& aCoordPairStr) { NS_ABORT_IF_FALSE(!mHaveReceivedCommands, "Not expecting requests for mid-path MoveTo commands"); mHaveReceivedCommands = true; float xVal, yVal; if (!ParseCoordinatePair(aCoordPairStr, xVal, yVal)) { return false; } mGfxContext.MoveTo(gfxPoint(xVal, yVal)); return true; }
void CopyableCanvasLayer::PaintWithOpacity(gfxContext* aContext, float aOpacity, Layer* aMaskLayer, gfxContext::GraphicsOperator aOperator) { if (!mSurface) { NS_WARNING("No valid surface to draw!"); return; } nsRefPtr<gfxPattern> pat = new gfxPattern(mSurface); pat->SetFilter(mFilter); pat->SetExtend(gfxPattern::EXTEND_PAD); gfxMatrix m; if (mNeedsYFlip) { m = aContext->CurrentMatrix(); aContext->Translate(gfxPoint(0.0, mBounds.height)); aContext->Scale(1.0, -1.0); } // If content opaque, then save off current operator and set to source. // This ensures that alpha is not applied even if the source surface // has an alpha channel gfxContext::GraphicsOperator savedOp; if (GetContentFlags() & CONTENT_OPAQUE) { savedOp = aContext->CurrentOperator(); aContext->SetOperator(gfxContext::OPERATOR_SOURCE); } AutoSetOperator setOperator(aContext, aOperator); aContext->NewPath(); // No need to snap here; our transform is already set up to snap our rect aContext->Rectangle(gfxRect(0, 0, mBounds.width, mBounds.height)); aContext->SetPattern(pat); FillWithMask(aContext, aOpacity, aMaskLayer); // Restore surface operator if (GetContentFlags() & CONTENT_OPAQUE) { aContext->SetOperator(savedOp); } if (mNeedsYFlip) { aContext->SetMatrix(m); } }
already_AddRefed<gfxContext> ThebesLayerBuffer::GetContextForQuadrantUpdate(const nsIntRect& aBounds) { nsRefPtr<gfxContext> ctx = new gfxContext(mBuffer); // Figure out which quadrant to draw in PRInt32 xBoundary = mBufferRect.XMost() - mBufferRotation.x; PRInt32 yBoundary = mBufferRect.YMost() - mBufferRotation.y; XSide sideX = aBounds.XMost() <= xBoundary ? RIGHT : LEFT; YSide sideY = aBounds.YMost() <= yBoundary ? BOTTOM : TOP; nsIntRect quadrantRect = GetQuadrantRectangle(sideX, sideY); NS_ASSERTION(quadrantRect.Contains(aBounds), "Messed up quadrants"); ctx->Translate(-gfxPoint(quadrantRect.x, quadrantRect.y)); return ctx.forget(); }
void nsDisplayCanvasBackground::Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) { nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame); nsPoint offset = ToReferenceFrame(); nsRect bgClipRect = frame->CanvasArea() + offset; if (mIsBottommostLayer && NS_GET_A(mExtraBackgroundColor) > 0) { aCtx->SetColor(mExtraBackgroundColor); aCtx->FillRect(bgClipRect); } bool snap; nsRect bounds = GetBounds(aBuilder, &snap); nsRenderingContext context; nsRefPtr<gfxContext> dest = aCtx->ThebesContext(); nsRefPtr<gfxASurface> surf; nsRefPtr<gfxContext> ctx; #ifndef MOZ_GFX_OPTIMIZE_MOBILE if (IsSingleFixedPositionImage(aBuilder, bgClipRect) && aBuilder->IsPaintingToWindow() && !aBuilder->IsCompositingCheap()) { surf = static_cast<gfxASurface*>(GetUnderlyingFrame()->Properties().Get(nsIFrame::CachedBackgroundImage())); nsRefPtr<gfxASurface> destSurf = dest->CurrentSurface(); if (surf && surf->GetType() == destSurf->GetType()) { BlitSurface(dest, mDestRect, surf); return; } surf = destSurf->CreateSimilarSurface(gfxASurface::CONTENT_COLOR_ALPHA, gfxIntSize(ceil(mDestRect.width), ceil(mDestRect.height))); if (surf) { ctx = new gfxContext(surf); ctx->Translate(-gfxPoint(mDestRect.x, mDestRect.y)); context.Init(aCtx->DeviceContext(), ctx); } } #endif nsCSSRendering::PaintBackground(mFrame->PresContext(), surf ? context : *aCtx, mFrame, surf ? bounds : mVisibleRect, nsRect(offset, mFrame->GetSize()), aBuilder->GetBackgroundPaintFlags(), &bgClipRect, mLayer); if (surf) { BlitSurface(dest, mDestRect, surf); GetUnderlyingFrame()->Properties().Set(nsIFrame::CachedBackgroundImage(), surf.forget().get()); GetUnderlyingFrame()->AddStateBits(NS_FRAME_HAS_CACHED_BACKGROUND); } }
void AsyncPanZoomController::GetContentTransformForFrame(const FrameMetrics& aFrame, const gfx3DMatrix& aRootTransform, const gfxSize& aWidgetSize, gfx3DMatrix* aTreeTransform, gfxPoint* aReverseViewTranslation) { // Scales on the root layer, on what's currently painted. float rootScaleX = aRootTransform.GetXScale(), rootScaleY = aRootTransform.GetYScale(); // Current local transform; this is not what's painted but rather what PZC has // transformed due to touches like panning or pinching. Eventually, the root // layer transform will become this during runtime, but we must wait for Gecko // to repaint. float localScaleX = mFrameMetrics.mResolution.width, localScaleY = mFrameMetrics.mResolution.height; // Handle transformations for asynchronous panning and zooming. We determine the // zoom used by Gecko from the transformation set on the root layer, and we // determine the scroll offset used by Gecko from the frame metrics of the // primary scrollable layer. We compare this to the desired zoom and scroll // offset in the view transform we obtained from Java in order to compute the // transformation we need to apply. float tempScaleDiffX = rootScaleX * localScaleX; float tempScaleDiffY = rootScaleY * localScaleY; nsIntPoint metricsScrollOffset(0, 0); if (aFrame.IsScrollable()) metricsScrollOffset = aFrame.mViewportScrollOffset; nsIntPoint scrollCompensation( mFrameMetrics.mViewportScrollOffset.x / rootScaleX - metricsScrollOffset.x, mFrameMetrics.mViewportScrollOffset.y / rootScaleY - metricsScrollOffset.y); ViewTransform treeTransform(-scrollCompensation, localScaleX, localScaleY); *aTreeTransform = gfx3DMatrix(treeTransform); float offsetX = mFrameMetrics.mViewportScrollOffset.x / tempScaleDiffX, offsetY = mFrameMetrics.mViewportScrollOffset.y / tempScaleDiffY; nsIntRect localContentRect = mFrameMetrics.mContentRect; offsetX = NS_MAX((float)localContentRect.x, NS_MIN(offsetX, (float)(localContentRect.XMost() - aWidgetSize.width))); offsetY = NS_MAX((float)localContentRect.y, NS_MIN(offsetY, (float)(localContentRect.YMost() - aWidgetSize.height))); *aReverseViewTranslation = gfxPoint(offsetX - metricsScrollOffset.x, offsetY - metricsScrollOffset.y); }
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(); nsRefPtr<gfxASurface> surf; nsRefPtr<gfxContext> ctx; 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(); surf = static_cast<gfxASurface*>(GetUnderlyingFrame()->Properties().Get(nsIFrame::CachedBackgroundImage())); nsRefPtr<gfxASurface> destSurf = dest->CurrentSurface(); if (surf && surf->GetType() == destSurf->GetType()) { BlitSurface(dest, destRect, surf); return; } surf = destSurf->CreateSimilarSurface(gfxASurface::CONTENT_COLOR_ALPHA, gfxIntSize(destRect.width, destRect.height)); if (surf) { ctx = new gfxContext(surf); ctx->Translate(-gfxPoint(destRect.x, destRect.y)); context.Init(aCtx->DeviceContext(), ctx); } } #endif PaintInternal(aBuilder, surf ? &context : aCtx, surf ? bgClipRect: mVisibleRect, &bgClipRect); if (surf) { BlitSurface(dest, destRect, surf); frame->Properties().Set(nsIFrame::CachedBackgroundImage(), surf.forget().get()); } }
gfxContext::gfxContext(gfxASurface *surface) : mSurface(surface) { MOZ_COUNT_CTOR(gfxContext); mCairo = cairo_create(surface->CairoSurface()); mFlags = surface->GetDefaultContextFlags(); if (mSurface->GetRotateForLandscape()) { // Rotate page 90 degrees to draw landscape page on portrait paper gfxIntSize size = mSurface->GetSize(); Translate(gfxPoint(0, size.width)); gfxMatrix matrix(0, -1, 1, 0, 0, 0); Multiply(matrix); } }
// Clip aTarget's image to its filter primitive subregion. // aModifiedRect contains all the pixels which might not be RGBA(0,0,0,0), // it's relative to the surface data. static void ClipTarget(nsSVGFilterInstance* aInstance, const nsSVGFE::Image* aTarget, const nsIntRect& aModifiedRect) { nsIntPoint surfaceTopLeft = aInstance->GetSurfaceRect().TopLeft(); NS_ASSERTION(aInstance->GetSurfaceRect().Contains(aModifiedRect + surfaceTopLeft), "Modified data area overflows the surface?"); nsIntRect clip = aModifiedRect; nsSVGUtils::ClipToGfxRect(&clip, aTarget->mFilterPrimitiveSubregion - gfxPoint(surfaceTopLeft.x, surfaceTopLeft.y)); ClearRect(aTarget->mImage, aModifiedRect.x, aModifiedRect.y, aModifiedRect.XMost(), clip.y); ClearRect(aTarget->mImage, aModifiedRect.x, clip.y, clip.x, clip.YMost()); ClearRect(aTarget->mImage, clip.XMost(), clip.y, aModifiedRect.XMost(), clip.YMost()); ClearRect(aTarget->mImage, aModifiedRect.x, clip.YMost(), aModifiedRect.XMost(), aModifiedRect.YMost()); }
nsSVGPathGeometryFrame::GetFrameForPoint(const nsPoint &aPoint) { PRUint16 fillRule, mask; // check if we're a clipPath - cheaper than IsClipChild(), and we shouldn't // get in here for other nondisplay children if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) { NS_ASSERTION(IsClipChild(), "should be in clipPath but we're not"); mask = HITTEST_MASK_FILL; fillRule = GetClipRule(); } else { mask = GetHittestMask(); if (!mask || (!(mask & HITTEST_MASK_FORCE_TEST) && !mRect.Contains(aPoint))) return nsnull; fillRule = GetStyleSVG()->mFillRule; } PRBool isHit = PR_FALSE; gfxContext context(nsSVGUtils::GetThebesComputationalSurface()); GeneratePath(&context); gfxPoint userSpacePoint = context.DeviceToUser(gfxPoint(PresContext()->AppUnitsToGfxUnits(aPoint.x), PresContext()->AppUnitsToGfxUnits(aPoint.y))); if (fillRule == NS_STYLE_FILL_RULE_EVENODD) context.SetFillRule(gfxContext::FILL_RULE_EVEN_ODD); else context.SetFillRule(gfxContext::FILL_RULE_WINDING); if (mask & HITTEST_MASK_FILL) isHit = context.PointInFill(userSpacePoint); if (!isHit && (mask & HITTEST_MASK_STROKE)) { SetupCairoStrokeHitGeometry(&context); isHit = context.PointInStroke(userSpacePoint); } if (isHit && nsSVGUtils::HitTestClip(this, aPoint)) return this; return nsnull; }
void gfxWindowsNativeDrawing::PaintToContext() { if (mRenderState == RENDER_STATE_NATIVE_DRAWING_DONE) { // nothing to do, it already went to the context mRenderState = RENDER_STATE_DONE; } else if (mRenderState == RENDER_STATE_ALPHA_RECOVERY_WHITE_DONE) { nsRefPtr<gfxImageSurface> black = mBlackSurface->GetAsImageSurface(); nsRefPtr<gfxImageSurface> white = mWhiteSurface->GetAsImageSurface(); if (!gfxAlphaRecovery::RecoverAlpha(black, white)) { NS_ERROR("Alpha recovery failure"); return; } nsRefPtr<gfxImageSurface> alphaSurface = new gfxImageSurface(black->Data(), black->GetSize(), black->Stride(), gfxASurface::ImageFormatARGB32); mContext->Save(); mContext->Translate(mNativeRect.TopLeft()); mContext->NewPath(); mContext->Rectangle(gfxRect(gfxPoint(0.0, 0.0), mNativeRect.Size())); nsRefPtr<gfxPattern> pat = new gfxPattern(alphaSurface); gfxMatrix m; m.Scale(mScale.width, mScale.height); pat->SetMatrix(m); if (mNativeDrawFlags & DO_NEAREST_NEIGHBOR_FILTERING) pat->SetFilter(gfxPattern::FILTER_FAST); pat->SetExtend(gfxPattern::EXTEND_PAD); mContext->SetPattern(pat); mContext->Fill(); mContext->Restore(); mRenderState = RENDER_STATE_DONE; } else { NS_ERROR("Invalid RenderState in gfxWindowsNativeDrawing::PaintToContext"); } }
already_AddRefed<gfxContext> RotatedContentBuffer::GetContextForQuadrantUpdate(const nsIntRect& aBounds, ContextSource aSource, nsIntPoint *aTopLeft) { if (!EnsureBuffer()) { return nullptr; } nsRefPtr<gfxContext> ctx; if (aSource == BUFFER_BOTH && HaveBufferOnWhite()) { if (!EnsureBufferOnWhite()) { return nullptr; } MOZ_ASSERT(mDTBuffer && mDTBufferOnWhite); RefPtr<DrawTarget> dualDT = Factory::CreateDualDrawTarget(mDTBuffer, mDTBufferOnWhite); ctx = new gfxContext(dualDT); } else if (aSource == BUFFER_WHITE) { if (!EnsureBufferOnWhite()) { return nullptr; } ctx = new gfxContext(mDTBufferOnWhite); } else { // BUFFER_BLACK, or BUFFER_BOTH with a single buffer. ctx = new gfxContext(mDTBuffer); } // Figure out which quadrant to draw in int32_t xBoundary = mBufferRect.XMost() - mBufferRotation.x; int32_t yBoundary = mBufferRect.YMost() - mBufferRotation.y; XSide sideX = aBounds.XMost() <= xBoundary ? RIGHT : LEFT; YSide sideY = aBounds.YMost() <= yBoundary ? BOTTOM : TOP; nsIntRect quadrantRect = GetQuadrantRectangle(sideX, sideY); NS_ASSERTION(quadrantRect.Contains(aBounds), "Messed up quadrants"); ctx->Translate(-gfxPoint(quadrantRect.x, quadrantRect.y)); if (aTopLeft) { *aTopLeft = nsIntPoint(quadrantRect.x, quadrantRect.y); } return ctx.forget(); }
void LayerManagerOGL::CopyToTarget(gfxContext *aTarget) { nsIntRect rect; mWidget->GetBounds(rect); GLint width = rect.width; GLint height = rect.height; if ((PRInt64(width) * PRInt64(height) * PRInt64(4)) > PR_INT32_MAX) { NS_ERROR("Widget size too big - integer overflow!"); return; } nsRefPtr<gfxImageSurface> imageSurface = new gfxImageSurface(gfxIntSize(width, height), gfxASurface::ImageFormatARGB32); mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mGLContext->IsDoubleBuffered() ? 0 : mBackBufferFBO); #ifndef USE_GLES2 // GLES2 promises that binding to any custom FBO will attach // to GL_COLOR_ATTACHMENT0 attachment point. if (mGLContext->IsDoubleBuffered()) { mGLContext->fReadBuffer(LOCAL_GL_BACK); } else { mGLContext->fReadBuffer(LOCAL_GL_COLOR_ATTACHMENT0); } #endif NS_ASSERTION(imageSurface->Stride() == width * 4, "Image Surfaces being created with weird stride!"); mGLContext->ReadPixelsIntoImageSurface(0, 0, width, height, imageSurface); aTarget->SetOperator(gfxContext::OPERATOR_SOURCE); aTarget->Scale(1.0, -1.0); aTarget->Translate(-gfxPoint(0.0, height)); aTarget->SetSource(imageSurface); aTarget->Paint(); }
/* virtual */ gfxMatrix SVGUseElement::PrependLocalTransformsTo(const gfxMatrix &aMatrix, TransformTypes aWhich) const { NS_ABORT_IF_FALSE(aWhich != eChildToUserSpace || aMatrix.IsIdentity(), "Skipping eUserSpaceToParent transforms makes no sense"); // 'transform' attribute: gfxMatrix fromUserSpace = SVGUseElementBase::PrependLocalTransformsTo(aMatrix, aWhich); if (aWhich == eUserSpaceToParent) { return fromUserSpace; } // our 'x' and 'y' attributes: float x, y; const_cast<SVGUseElement*>(this)->GetAnimatedLengthValues(&x, &y, nullptr); gfxMatrix toUserSpace = gfxMatrix().Translate(gfxPoint(x, y)); if (aWhich == eChildToUserSpace) { return toUserSpace; } NS_ABORT_IF_FALSE(aWhich == eAllTransforms, "Unknown TransformTypes"); return toUserSpace * fromUserSpace; }
// Helper method for Add & CreateMatrix inline static void GetAngleAndPointAtDistance(gfxFlattenedPath* aPath, float aDistance, RotateType aRotateType, gfxFloat& aRotateAngle, // in & out-param. gfxPoint& aPoint) // out-param. { gfxFloat tangentAngle; // NOTE: "0.0" below is distance-off-the-path. (see FindPoint documentation) aPoint = aPath->FindPoint(gfxPoint(aDistance, 0.0), &tangentAngle); // Update aRotateAngle if it's auto/auto-reverse switch (aRotateType) { case eRotateType_Explicit: // Leave aRotateAngle as-is. break; case eRotateType_Auto: aRotateAngle = tangentAngle; break; case eRotateType_AutoReverse: aRotateAngle = M_PI + tangentAngle; break; } }
NS_IMETHODIMP nsThebesRenderingContext::DrawLine(nscoord aX0, nscoord aY0, nscoord aX1, nscoord aY1) { PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::DrawLine %d %d %d %d\n", this, aX0, aY0, aX1, aY1)); gfxPoint p0 = gfxPoint(FROM_TWIPS(aX0), FROM_TWIPS(aY0)); gfxPoint p1 = gfxPoint(FROM_TWIPS(aX1), FROM_TWIPS(aY1)); // we can't draw thick lines with gfx, so we always assume we want pixel-aligned // lines if the rendering context is at 1.0 scale gfxMatrix savedMatrix = mThebes->CurrentMatrix(); if (!savedMatrix.HasNonTranslation()) { p0 = mThebes->UserToDevice(p0); p1 = mThebes->UserToDevice(p1); p0.Round(); p1.Round(); mThebes->IdentityMatrix(); mThebes->NewPath(); // snap straight lines if (p0.x == p1.x) { mThebes->Line(p0 + gfxPoint(0.5, 0), p1 + gfxPoint(0.5, 0)); } else if (p0.y == p1.y) { mThebes->Line(p0 + gfxPoint(0, 0.5), p1 + gfxPoint(0, 0.5)); } else { mThebes->Line(p0, p1); } mThebes->Stroke(); mThebes->SetMatrix(savedMatrix); } else { mThebes->NewPath(); mThebes->Line(p0, p1); mThebes->Stroke(); } return NS_OK; }
nsSVGForeignObjectFrame::GetFrameForPoint(const nsPoint &aPoint) { if (IsDisabled() || (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)) return nsnull; nsIFrame* kid = GetFirstPrincipalChild(); if (!kid) return nsnull; float x, y, width, height; static_cast<nsSVGElement*>(mContent)-> GetAnimatedLengthValues(&x, &y, &width, &height, nsnull); gfxMatrix tm = GetCanvasTM().Invert(); if (tm.IsSingular()) return nsnull; // Convert aPoint from app units in canvas space to user space: gfxPoint pt = gfxPoint(aPoint.x, aPoint.y) / PresContext()->AppUnitsPerDevPixel(); pt = tm.Transform(pt); if (!gfxRect(0.0f, 0.0f, width, height).Contains(pt)) return nsnull; // Convert pt to app units in *local* space: pt = pt * nsPresContext::AppUnitsPerCSSPixel(); nsPoint point = nsPoint(NSToIntRound(pt.x), NSToIntRound(pt.y)); nsIFrame *frame = nsLayoutUtils::GetFrameForPoint(kid, point); if (frame && nsSVGUtils::HitTestClip(this, aPoint)) return frame; return nsnull; }
void BasicShadowCanvasLayer::Paint(gfxContext* aContext, Layer* aMaskLayer) { NS_ASSERTION(BasicManager()->InDrawing(), "Can only draw in drawing phase"); if (!IsSurfaceDescriptorValid(mFrontSurface)) { return; } AutoOpenSurface autoSurface(OPEN_READ_ONLY, mFrontSurface); nsRefPtr<gfxPattern> pat = new gfxPattern(autoSurface.Get()); pat->SetFilter(mFilter); pat->SetExtend(gfxPattern::EXTEND_PAD); gfxRect r(0, 0, mBounds.width, mBounds.height); gfxMatrix m; if (mNeedsYFlip) { m = aContext->CurrentMatrix(); aContext->Translate(gfxPoint(0.0, mBounds.height)); aContext->Scale(1.0, -1.0); } AutoSetOperator setOperator(aContext, GetOperator()); aContext->NewPath(); // No need to snap here; our transform has already taken care of it aContext->Rectangle(r); aContext->SetPattern(pat); FillWithMask(aContext, GetEffectiveOpacity(), aMaskLayer); if (mNeedsYFlip) { aContext->SetMatrix(m); } }
already_AddRefed<nsISVGPoint> SVGPathElement::GetPointAtLength(float distance, ErrorResult& rv) { nsRefPtr<gfxFlattenedPath> flat = GetFlattenedPath(gfxMatrix()); if (!flat) { rv.Throw(NS_ERROR_FAILURE); return nullptr; } float totalLength = flat->GetLength(); if (mPathLength.IsExplicitlySet()) { float pathLength = mPathLength.GetAnimValue(); if (pathLength <= 0) { rv.Throw(NS_ERROR_FAILURE); return nullptr; } distance *= totalLength / pathLength; } distance = std::max(0.f, distance); distance = std::min(totalLength, distance); nsCOMPtr<nsISVGPoint> point = new DOMSVGPoint(flat->FindPoint(gfxPoint(distance, 0))); return point.forget(); }
void nsRenderingContext::DrawLine(nscoord aX0, nscoord aY0, nscoord aX1, nscoord aY1) { gfxPoint p0 = gfxPoint(FROM_TWIPS(aX0), FROM_TWIPS(aY0)); gfxPoint p1 = gfxPoint(FROM_TWIPS(aX1), FROM_TWIPS(aY1)); // we can't draw thick lines with gfx, so we always assume we want // pixel-aligned lines if the rendering context is at 1.0 scale gfxMatrix savedMatrix = mThebes->CurrentMatrix(); if (!savedMatrix.HasNonTranslation()) { p0 = mThebes->UserToDevice(p0); p1 = mThebes->UserToDevice(p1); p0.Round(); p1.Round(); mThebes->IdentityMatrix(); mThebes->NewPath(); // snap straight lines if (p0.x == p1.x) { mThebes->Line(p0 + gfxPoint(0.5, 0), p1 + gfxPoint(0.5, 0)); } else if (p0.y == p1.y) { mThebes->Line(p0 + gfxPoint(0, 0.5), p1 + gfxPoint(0, 0.5)); } else { mThebes->Line(p0, p1); } mThebes->Stroke(); mThebes->SetMatrix(savedMatrix); } else { mThebes->NewPath(); mThebes->Line(p0, p1); mThebes->Stroke(); } }