float nsSVGUtils::ObjectSpace(const gfxRect &aRect, const nsSVGLength2 *aLength) { float fraction, axis; switch (aLength->GetCtxType()) { case X: axis = aRect.Width(); break; case Y: axis = aRect.Height(); break; case XY: axis = float(ComputeNormalizedHypotenuse(aRect.Width(), aRect.Height())); break; default: NS_NOTREACHED("unexpected ctx type"); axis = 0.0f; break; } if (aLength->IsPercentage()) { fraction = aLength->GetAnimValInSpecifiedUnits() / 100; } else { fraction = aLength->GetAnimValue(static_cast<nsSVGSVGElement*> (nsnull)); } return fraction * axis; }
nsresult NS_NewSVGRect(mozilla::dom::SVGRect** result, const gfxRect& rect) { return NS_NewSVGRect(result, rect.X(), rect.Y(), rect.Width(), rect.Height()); }
gfxRect gfx3DMatrix::ProjectRectBounds(const gfxRect& aRect) const { gfxPoint points[4]; points[0] = ProjectPoint(aRect.TopLeft()); points[1] = ProjectPoint(gfxPoint(aRect.X() + aRect.Width(), aRect.Y())); points[2] = ProjectPoint(gfxPoint(aRect.X(), aRect.Y() + aRect.Height())); points[3] = ProjectPoint(gfxPoint(aRect.X() + aRect.Width(), aRect.Y() + aRect.Height())); gfxFloat min_x, max_x; gfxFloat min_y, max_y; min_x = max_x = points[0].x; min_y = max_y = points[0].y; for (int i=1; i<4; i++) { min_x = min(points[i].x, min_x); max_x = max(points[i].x, max_x); min_y = min(points[i].y, min_y); max_y = max(points[i].y, max_y); } return gfxRect(min_x, min_y, max_x - min_x, max_y - min_y); }
nsresult NS_NewSVGRect(nsIDOMSVGRect** result, const gfxRect& rect) { return NS_NewSVGRect(result, rect.X(), rect.Y(), rect.Width(), rect.Height()); }
// clipping void gfxContext::Clip(const gfxRect& rect) { cairo_new_path(mCairo); cairo_rectangle(mCairo, rect.X(), rect.Y(), rect.Width(), rect.Height()); cairo_clip(mCairo); }
imgFrame::SurfaceWithFormat imgFrame::SurfaceForDrawing(bool aDoPadding, bool aDoPartialDecode, bool aDoTile, const nsIntMargin& aPadding, gfxMatrix& aUserSpaceToImageSpace, gfxRect& aFill, gfxRect& aSubimage, gfxRect& aSourceRect, gfxRect& aImageRect) { gfxIntSize size(PRInt32(aImageRect.Width()), PRInt32(aImageRect.Height())); if (!aDoPadding && !aDoPartialDecode) { NS_ASSERTION(!mSinglePixel, "This should already have been handled"); return SurfaceWithFormat(new gfxSurfaceDrawable(ThebesSurface(), size), mFormat); } gfxRect available = gfxRect(mDecoded.x, mDecoded.y, mDecoded.width, mDecoded.height); if (aDoTile || mSinglePixel) { // Create a temporary surface. // Give this surface an alpha channel because there are // transparent pixels in the padding or undecoded area gfxImageSurface::gfxImageFormat format = gfxASurface::ImageFormatARGB32; nsRefPtr<gfxASurface> surface = gfxPlatform::GetPlatform()->CreateOffscreenSurface(size, gfxImageSurface::ContentFromFormat(format)); if (!surface || surface->CairoStatus()) return SurfaceWithFormat(); // Fill 'available' with whatever we've got gfxContext tmpCtx(surface); tmpCtx.SetOperator(gfxContext::OPERATOR_SOURCE); if (mSinglePixel) { tmpCtx.SetDeviceColor(mSinglePixelColor); } else { tmpCtx.SetSource(ThebesSurface(), gfxPoint(aPadding.left, aPadding.top)); } tmpCtx.Rectangle(available); tmpCtx.Fill(); return SurfaceWithFormat(new gfxSurfaceDrawable(surface, size), format); } // Not tiling, and we have a surface, so we can account for // padding and/or a partial decode just by twiddling parameters. // First, update our user-space fill rect. aSourceRect = aSourceRect.Intersect(available); gfxMatrix imageSpaceToUserSpace = aUserSpaceToImageSpace; imageSpaceToUserSpace.Invert(); aFill = imageSpaceToUserSpace.Transform(aSourceRect); aSubimage = aSubimage.Intersect(available) - gfxPoint(aPadding.left, aPadding.top); aUserSpaceToImageSpace.Multiply(gfxMatrix().Translate(-gfxPoint(aPadding.left, aPadding.top))); aSourceRect = aSourceRect - gfxPoint(aPadding.left, aPadding.top); aImageRect = gfxRect(0, 0, mSize.width, mSize.height); gfxIntSize availableSize(mDecoded.width, mDecoded.height); return SurfaceWithFormat(new gfxSurfaceDrawable(ThebesSurface(), availableSize), mFormat); }
void gfxFontMissingGlyphs::DrawMissingGlyph(gfxContext *aContext, const gfxRect& aRect, uint32_t aChar) { aContext->Save(); gfxRGBA currentColor; if (!aContext->GetDeviceColor(currentColor)) { // We're currently drawing with some kind of pattern... Just draw // the missing-glyph data in black. currentColor = gfxRGBA(0,0,0,1); } // Stroke a rectangle so that the stroke's left edge is inset one pixel // from the left edge of the glyph box and the stroke's right edge // is inset one pixel from the right edge of the glyph box. gfxFloat halfBorderWidth = BOX_BORDER_WIDTH/2.0; gfxFloat borderLeft = aRect.X() + BOX_HORIZONTAL_INSET + halfBorderWidth; gfxFloat borderRight = aRect.XMost() - BOX_HORIZONTAL_INSET - halfBorderWidth; gfxRect borderStrokeRect(borderLeft, aRect.Y() + halfBorderWidth, borderRight - borderLeft, aRect.Height() - 2*halfBorderWidth); if (!borderStrokeRect.IsEmpty()) { aContext->SetLineWidth(BOX_BORDER_WIDTH); aContext->SetDash(gfxContext::gfxLineSolid); aContext->SetLineCap(gfxContext::LINE_CAP_SQUARE); aContext->SetLineJoin(gfxContext::LINE_JOIN_MITER); gfxRGBA color = currentColor; color.a *= BOX_BORDER_OPACITY; aContext->SetDeviceColor(color); aContext->NewPath(); aContext->Rectangle(borderStrokeRect); #ifdef MOZ_GFX_OPTIMIZE_MOBILE aContext->Fill(); #else aContext->Stroke(); #endif } #ifndef MOZ_GFX_OPTIMIZE_MOBILE gfxPoint center(aRect.X() + aRect.Width()/2, aRect.Y() + aRect.Height()/2); gfxFloat halfGap = HEX_CHAR_GAP/2.0; gfxFloat top = -(MINIFONT_HEIGHT + halfGap); if (aChar < 0x10000) { if (aRect.Width() >= 2*MINIFONT_WIDTH + HEX_CHAR_GAP && aRect.Height() >= 2*MINIFONT_HEIGHT + HEX_CHAR_GAP) { // Draw 4 digits for BMP aContext->SetDeviceColor(currentColor); gfxFloat left = -(MINIFONT_WIDTH + halfGap); DrawHexChar(aContext, center + gfxPoint(left, top), (aChar >> 12) & 0xF); DrawHexChar(aContext, center + gfxPoint(halfGap, top), (aChar >> 8) & 0xF); DrawHexChar(aContext, center + gfxPoint(left, halfGap), (aChar >> 4) & 0xF); DrawHexChar(aContext, center + gfxPoint(halfGap, halfGap), aChar & 0xF); } } else {
void gfxASurface::MarkDirty(const gfxRect& r) { cairo_surface_mark_dirty_rectangle(mSurface, (int) r.X(), (int) r.Y(), (int) r.Width(), (int) r.Height()); }
nsRect nsSVGUtils::ToAppPixelRect(nsPresContext *aPresContext, const gfxRect& rect) { return nsRect(aPresContext->DevPixelsToAppUnits(NSToIntFloor(rect.X())), aPresContext->DevPixelsToAppUnits(NSToIntFloor(rect.Y())), aPresContext->DevPixelsToAppUnits(NSToIntCeil(rect.XMost()) - NSToIntFloor(rect.X())), aPresContext->DevPixelsToAppUnits(NSToIntCeil(rect.YMost()) - NSToIntFloor(rect.Y()))); }
void gfxASurface::MarkDirty(const gfxRect& r) { if (!mSurfaceValid) return; cairo_surface_mark_dirty_rectangle(mSurface, (int) r.X(), (int) r.Y(), (int) r.Width(), (int) r.Height()); gfxPlatform::ClearSourceSurfaceForSurface(this); }
gfxMatrix nsSVGPatternFrame::ConstructCTM(const gfxRect &callerBBox, const gfxMatrix &callerCTM, nsIFrame *aTarget) { gfxMatrix tCTM; nsSVGSVGElement *ctx = nsnull; nsIContent* targetContent = aTarget->GetContent(); // The objectBoundingBox conversion must be handled in the CTM: if (GetEnumValue(nsSVGPatternElement::PATTERNCONTENTUNITS) == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { tCTM.Scale(callerBBox.Width(), callerBBox.Height()); } else { if (targetContent->IsSVG()) { ctx = static_cast<nsSVGElement*>(targetContent)->GetCtx(); } float scale = nsSVGUtils::MaxExpansion(callerCTM); tCTM.Scale(scale, scale); } const nsSVGViewBoxRect viewBox = GetViewBox().GetAnimValue(); if (viewBox.height <= 0.0f && viewBox.width <= 0.0f) { return tCTM; } float viewportWidth, viewportHeight; if (targetContent->IsSVG()) { // If we're dealing with an SVG target only retrieve the context once. // Calling the nsIFrame* variant of GetAnimValue would look it up on // every call. viewportWidth = GetLengthValue(nsSVGPatternElement::WIDTH)->GetAnimValue(ctx); viewportHeight = GetLengthValue(nsSVGPatternElement::HEIGHT)->GetAnimValue(ctx); } else { // No SVG target, call the nsIFrame* variant of GetAnimValue. viewportWidth = GetLengthValue(nsSVGPatternElement::WIDTH)->GetAnimValue(aTarget); viewportHeight = GetLengthValue(nsSVGPatternElement::HEIGHT)->GetAnimValue(aTarget); } gfxMatrix tm = nsSVGUtils::GetViewBoxTransform( static_cast<nsSVGPatternElement*>(mContent), viewportWidth, viewportHeight, viewBox.x, viewBox.y, viewBox.width, viewBox.height, GetPreserveAspectRatio()); return tm * tCTM; }
gfxRect gfxRect::Union(const gfxRect& aRect) const { if (IsEmpty()) return aRect; if (aRect.IsEmpty()) return *this; gfxFloat x = PR_MIN(aRect.X(), X()); gfxFloat xmost = PR_MAX(aRect.XMost(), XMost()); gfxFloat y = PR_MIN(aRect.Y(), Y()); gfxFloat ymost = PR_MAX(aRect.YMost(), YMost()); return gfxRect(x, y, xmost - x, ymost - y); }
gfx3DMatrix Layer::SnapTransform(const gfx3DMatrix& aTransform, const gfxRect& aSnapRect, gfxMatrix* aResidualTransform) { if (aResidualTransform) { *aResidualTransform = gfxMatrix(); } gfxMatrix matrix2D; gfx3DMatrix result; if (mManager->IsSnappingEffectiveTransforms() && aTransform.Is2D(&matrix2D) && matrix2D.HasNonIntegerTranslation() && !matrix2D.IsSingular() && !matrix2D.HasNonAxisAlignedTransform()) { gfxMatrix snappedMatrix; gfxPoint topLeft = matrix2D.Transform(aSnapRect.TopLeft()); topLeft.Round(); // first compute scale factors that scale aSnapRect to the snapped rect if (aSnapRect.IsEmpty()) { snappedMatrix.xx = matrix2D.xx; snappedMatrix.yy = matrix2D.yy; } else { gfxPoint bottomRight = matrix2D.Transform(aSnapRect.BottomRight()); bottomRight.Round(); snappedMatrix.xx = (bottomRight.x - topLeft.x)/aSnapRect.Width(); snappedMatrix.yy = (bottomRight.y - topLeft.y)/aSnapRect.Height(); } // compute translation factors that will move aSnapRect to the snapped rect // given those scale factors snappedMatrix.x0 = topLeft.x - aSnapRect.pos.x*snappedMatrix.xx; snappedMatrix.y0 = topLeft.y - aSnapRect.pos.y*snappedMatrix.yy; result = gfx3DMatrix::From2D(snappedMatrix); if (aResidualTransform && !snappedMatrix.IsSingular()) { // set aResidualTransform so that aResidual * snappedMatrix == matrix2D. // (i.e., appying snappedMatrix after aResidualTransform gives the // ideal transform. gfxMatrix snappedMatrixInverse = snappedMatrix; snappedMatrixInverse.Invert(); *aResidualTransform = matrix2D * snappedMatrixInverse; } } else { result = aTransform; } return result; }
gfxQuad gfx3DMatrix::TransformRect(const gfxRect& aRect) const { gfxPoint points[4]; points[0] = Transform(aRect.TopLeft()); points[1] = Transform(gfxPoint(aRect.X() + aRect.Width(), aRect.Y())); points[2] = Transform(gfxPoint(aRect.X() + aRect.Width(), aRect.Y() + aRect.Height())); points[3] = Transform(gfxPoint(aRect.X(), aRect.Y() + aRect.Height())); // Could this ever result in lines that intersect? I don't think so. return gfxQuad(points[0], points[1], points[2], points[3]); }
gfxRect nsSVGUtils::GetRelativeRect(PRUint16 aUnits, const nsSVGLength2 *aXYWH, const gfxRect &aBBox, nsIFrame *aFrame) { float x, y, width, height; if (aUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { x = aBBox.X() + ObjectSpace(aBBox, &aXYWH[0]); y = aBBox.Y() + ObjectSpace(aBBox, &aXYWH[1]); width = ObjectSpace(aBBox, &aXYWH[2]); height = ObjectSpace(aBBox, &aXYWH[3]); } else { x = nsSVGUtils::UserSpace(aFrame, &aXYWH[0]); y = nsSVGUtils::UserSpace(aFrame, &aXYWH[1]); width = nsSVGUtils::UserSpace(aFrame, &aXYWH[2]); height = nsSVGUtils::UserSpace(aFrame, &aXYWH[3]); } return gfxRect(x, y, width, height); }
gfxRect gfxRect::Intersect(const gfxRect& aRect) const { gfxRect result(0,0,0,0); gfxFloat x = PR_MAX(aRect.X(), X()); gfxFloat xmost = PR_MIN(aRect.XMost(), XMost()); if (x >= xmost) return result; gfxFloat y = PR_MAX(aRect.Y(), Y()); gfxFloat ymost = PR_MIN(aRect.YMost(), YMost()); if (y >= ymost) return result; result = gfxRect(x, y, xmost - x, ymost - y); return result; }
// XXX snapToPixels is only valid when snapping for filled // rectangles and for even-width stroked rectangles. // For odd-width stroked rectangles, we need to offset x/y by // 0.5... void gfxContext::Rectangle(const gfxRect& rect, bool snapToPixels) { if (snapToPixels) { gfxRect snappedRect(rect); if (UserToDevicePixelSnapped(snappedRect, PR_TRUE)) { cairo_matrix_t mat; cairo_get_matrix(mCairo, &mat); cairo_identity_matrix(mCairo); Rectangle(snappedRect); cairo_set_matrix(mCairo, &mat); return; } } cairo_rectangle(mCairo, rect.X(), rect.Y(), rect.Width(), rect.Height()); }
void gfxASurface::SetOpaqueRect(const gfxRect& aRect) { if (aRect.IsEmpty()) { mOpaqueRect = nullptr; } else if (!!mOpaqueRect) { *mOpaqueRect = aRect; } else { mOpaqueRect = MakeUnique<gfxRect>(aRect); } }
gfx3DMatrix Layer::SnapTransform(const gfx3DMatrix& aTransform, const gfxRect& aSnapRect, gfxMatrix* aResidualTransform) { if (aResidualTransform) { *aResidualTransform = gfxMatrix(); } gfxMatrix matrix2D; gfx3DMatrix result; if (!(mContentFlags & CONTENT_DISABLE_TRANSFORM_SNAPPING) && mManager->IsSnappingEffectiveTransforms() && aTransform.Is2D(&matrix2D) && gfxSize(1.0, 1.0) <= aSnapRect.Size() && matrix2D.PreservesAxisAlignedRectangles()) { gfxPoint transformedTopLeft = matrix2D.Transform(aSnapRect.TopLeft()); transformedTopLeft.Round(); gfxPoint transformedTopRight = matrix2D.Transform(aSnapRect.TopRight()); transformedTopRight.Round(); gfxPoint transformedBottomRight = matrix2D.Transform(aSnapRect.BottomRight()); transformedBottomRight.Round(); gfxMatrix snappedMatrix = gfxUtils::TransformRectToRect(aSnapRect, transformedTopLeft, transformedTopRight, transformedBottomRight); result = gfx3DMatrix::From2D(snappedMatrix); if (aResidualTransform && !snappedMatrix.IsSingular()) { // set aResidualTransform so that aResidual * snappedMatrix == matrix2D. // (i.e., appying snappedMatrix after aResidualTransform gives the // ideal transform. gfxMatrix snappedMatrixInverse = snappedMatrix; snappedMatrixInverse.Invert(); *aResidualTransform = matrix2D * snappedMatrixInverse; } } else { result = aTransform; } return result; }
bool imgFrame::Draw(gfxContext *aContext, GraphicsFilter aFilter, const gfxMatrix &aUserSpaceToImageSpace, const gfxRect& aFill, const nsIntMargin &aPadding, const nsIntRect &aSubimage, uint32_t aImageFlags) { PROFILER_LABEL("image", "imgFrame::Draw"); NS_ASSERTION(!aFill.IsEmpty(), "zero dest size --- fix caller"); NS_ASSERTION(!aSubimage.IsEmpty(), "zero source size --- fix caller"); NS_ASSERTION(!mPalettedImageData, "Directly drawing a paletted image!"); bool doPadding = aPadding != nsIntMargin(0,0,0,0); bool doPartialDecode = !ImageComplete(); if (mSinglePixel && !doPadding && !doPartialDecode) { DoSingleColorFastPath(aContext, mSinglePixelColor, aFill); return true; } gfxMatrix userSpaceToImageSpace = aUserSpaceToImageSpace; gfxRect sourceRect = userSpaceToImageSpace.TransformBounds(aFill); gfxRect imageRect(0, 0, mSize.width + aPadding.LeftRight(), mSize.height + aPadding.TopBottom()); gfxRect subimage(aSubimage.x, aSubimage.y, aSubimage.width, aSubimage.height); gfxRect fill = aFill; NS_ASSERTION(!sourceRect.Intersect(subimage).IsEmpty(), "We must be allowed to sample *some* source pixels!"); nsRefPtr<gfxASurface> surf; if (!mSinglePixel) { surf = ThebesSurface(); if (!surf) return false; } bool doTile = !imageRect.Contains(sourceRect) && !(aImageFlags & imgIContainer::FLAG_CLAMP); SurfaceWithFormat surfaceResult = SurfaceForDrawing(doPadding, doPartialDecode, doTile, aPadding, userSpaceToImageSpace, fill, subimage, sourceRect, imageRect, surf); if (surfaceResult.IsValid()) { gfxUtils::DrawPixelSnapped(aContext, surfaceResult.mDrawable, userSpaceToImageSpace, subimage, sourceRect, imageRect, fill, surfaceResult.mFormat, aFilter, aImageFlags); } return true; }
// Given the matrix for the pattern element's own transform, this returns a // combined matrix including the transforms applicable to its target. static Matrix GetPatternMatrix(uint16_t aPatternUnits, const Matrix &patternTransform, const gfxRect &bbox, const gfxRect &callerBBox, const Matrix &callerCTM) { // We really want the pattern matrix to handle translations gfxFloat minx = bbox.X(); gfxFloat miny = bbox.Y(); if (aPatternUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { minx += callerBBox.X(); miny += callerBBox.Y(); } float scale = 1.0f / MaxExpansion(callerCTM); Matrix patternMatrix = patternTransform; patternMatrix.PreScale(scale, scale); patternMatrix.PreTranslate(minx, miny); return patternMatrix; }
// Given the matrix for the pattern element's own transform, this returns a // combined matrix including the transforms applicable to its target. static gfxMatrix GetPatternMatrix(uint16_t aPatternUnits, const gfxMatrix &patternTransform, const gfxRect &bbox, const gfxRect &callerBBox, const gfxMatrix &callerCTM) { // We really want the pattern matrix to handle translations gfxFloat minx = bbox.X(); gfxFloat miny = bbox.Y(); if (aPatternUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { minx += callerBBox.X(); miny += callerBBox.Y(); } float scale = 1.0f / nsSVGUtils::MaxExpansion(callerCTM); gfxMatrix patternMatrix = patternTransform; patternMatrix.Scale(scale, scale); patternMatrix.Translate(gfxPoint(minx, miny)); return patternMatrix; }
// Given the matrix for the pattern element's own transform, this returns a // combined matrix including the transforms applicable to its target. gfxMatrix nsSVGPatternFrame::GetPatternMatrix(const gfxMatrix &patternTransform, const gfxRect &bbox, const gfxRect &callerBBox, const gfxMatrix &callerCTM) { // We really want the pattern matrix to handle translations gfxFloat minx = bbox.X(); gfxFloat miny = bbox.Y(); PRUint16 type = GetEnumValue(nsSVGPatternElement::PATTERNUNITS); if (type == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { minx += callerBBox.X(); miny += callerBBox.Y(); } float scale = 1.0f / nsSVGUtils::MaxExpansion(callerCTM); gfxMatrix patternMatrix = patternTransform; patternMatrix.Scale(scale, scale); patternMatrix.Translate(gfxPoint(minx, miny)); return patternMatrix; }
gfxRect gfxContext::UserToDevice(const gfxRect& rect) const { double xmin = rect.X(), ymin = rect.Y(), xmax = rect.XMost(), ymax = rect.YMost(); double x[3], y[3]; x[0] = xmin; y[0] = ymax; x[1] = xmax; y[1] = ymax; x[2] = xmax; y[2] = ymin; cairo_user_to_device(mCairo, &xmin, &ymin); xmax = xmin; ymax = ymin; for (int i = 0; i < 3; i++) { cairo_user_to_device(mCairo, &x[i], &y[i]); xmin = NS_MIN(xmin, x[i]); xmax = NS_MAX(xmax, x[i]); ymin = NS_MIN(ymin, y[i]); ymax = NS_MAX(ymax, y[i]); } return gfxRect(xmin, ymin, xmax - xmin, ymax - ymin); }
Matrix4x4 Layer::SnapTransform(const Matrix4x4& aTransform, const gfxRect& aSnapRect, Matrix* aResidualTransform) { if (aResidualTransform) { *aResidualTransform = Matrix(); } Matrix matrix2D; Matrix4x4 result; if (mManager->IsSnappingEffectiveTransforms() && aTransform.Is2D(&matrix2D) && gfx::Size(1.0, 1.0) <= ToSize(aSnapRect.Size()) && matrix2D.PreservesAxisAlignedRectangles()) { IntPoint transformedTopLeft = RoundedToInt(matrix2D * ToPoint(aSnapRect.TopLeft())); IntPoint transformedTopRight = RoundedToInt(matrix2D * ToPoint(aSnapRect.TopRight())); IntPoint transformedBottomRight = RoundedToInt(matrix2D * ToPoint(aSnapRect.BottomRight())); Matrix snappedMatrix = gfxUtils::TransformRectToRect(aSnapRect, transformedTopLeft, transformedTopRight, transformedBottomRight); result = Matrix4x4::From2D(snappedMatrix); if (aResidualTransform && !snappedMatrix.IsSingular()) { // set aResidualTransform so that aResidual * snappedMatrix == matrix2D. // (i.e., appying snappedMatrix after aResidualTransform gives the // ideal transform. Matrix snappedMatrixInverse = snappedMatrix; snappedMatrixInverse.Invert(); *aResidualTransform = matrix2D * snappedMatrixInverse; } } else { result = aTransform; } return result; }
gfxRect gfxMatrix::TransformBounds(const gfxRect& rect) const { /* Code taken from cairo-matrix.c, _cairo_matrix_transform_bounding_box isn't public */ int i; double quad_x[4], quad_y[4]; double min_x, max_x; double min_y, max_y; quad_x[0] = rect.X(); quad_y[0] = rect.Y(); cairo_matrix_transform_point (CONST_CAIRO_MATRIX(this), &quad_x[0], &quad_y[0]); quad_x[1] = rect.XMost(); quad_y[1] = rect.Y(); cairo_matrix_transform_point (CONST_CAIRO_MATRIX(this), &quad_x[1], &quad_y[1]); quad_x[2] = rect.X(); quad_y[2] = rect.YMost(); cairo_matrix_transform_point (CONST_CAIRO_MATRIX(this), &quad_x[2], &quad_y[2]); quad_x[3] = rect.XMost(); quad_y[3] = rect.YMost(); cairo_matrix_transform_point (CONST_CAIRO_MATRIX(this), &quad_x[3], &quad_y[3]); min_x = max_x = quad_x[0]; min_y = max_y = quad_y[0]; for (i = 1; i < 4; i++) { if (quad_x[i] < min_x) min_x = quad_x[i]; if (quad_x[i] > max_x) max_x = quad_x[i]; if (quad_y[i] < min_y) min_y = quad_y[i]; if (quad_y[i] > max_y) max_y = quad_y[i]; } return gfxRect(min_x, min_y, max_x - min_x, max_y - min_y); }
// Return the largest rectangle that fits in aRect and has the // same aspect ratio as aRatio, centered at the center of aRect static gfxRect CorrectForAspectRatio(const gfxRect& aRect, const nsIntSize& aRatio) { NS_ASSERTION(aRatio.width > 0 && aRatio.height > 0 && !aRect.IsEmpty(), "Nothing to draw"); // Choose scale factor that scales aRatio to just fit into aRect gfxFloat scale = std::min(aRect.Width()/aRatio.width, aRect.Height()/aRatio.height); gfxSize scaledRatio(scale*aRatio.width, scale*aRatio.height); gfxPoint topLeft((aRect.Width() - scaledRatio.width)/2, (aRect.Height() - scaledRatio.height)/2); return gfxRect(aRect.TopLeft() + topLeft, scaledRatio); }
already_AddRefed<gfxContext> gfxCachedTempSurface::Get(gfxASurface::gfxContentType aContentType, const gfxRect& aRect, gfxASurface* aSimilarTo) { if (mSurface) { /* Verify the current buffer is valid for this purpose */ if (mSize.width < aRect.width || mSize.height < aRect.height || mSurface->GetContentType() != aContentType) { mSurface = nsnull; } else { NS_ASSERTION(mType == aSimilarTo->GetType(), "Unexpected surface type change"); } } bool cleared = false; if (!mSurface) { mSize = gfxIntSize(PRInt32(ceil(aRect.width)), PRInt32(ceil(aRect.height))); mSurface = aSimilarTo->CreateSimilarSurface(aContentType, mSize); if (!mSurface) return nsnull; cleared = PR_TRUE; #ifdef DEBUG mType = aSimilarTo->GetType(); #endif } mSurface->SetDeviceOffset(-aRect.TopLeft()); nsRefPtr<gfxContext> ctx = new gfxContext(mSurface); ctx->Rectangle(aRect); ctx->Clip(); if (!cleared && aContentType != gfxASurface::CONTENT_COLOR) { ctx->SetOperator(gfxContext::OPERATOR_CLEAR); ctx->Paint(); ctx->SetOperator(gfxContext::OPERATOR_OVER); } CachedSurfaceExpirationTracker::MarkSurfaceUsed(this); return ctx.forget(); }
void imgFrame::Draw(gfxContext *aContext, gfxPattern::GraphicsFilter aFilter, const gfxMatrix &aUserSpaceToImageSpace, const gfxRect& aFill, const nsIntMargin &aPadding, const nsIntRect &aSubimage) { NS_ASSERTION(!aFill.IsEmpty(), "zero dest size --- fix caller"); NS_ASSERTION(!aSubimage.IsEmpty(), "zero source size --- fix caller"); NS_ASSERTION(!mPalettedImageData, "Directly drawing a paletted image!"); bool doPadding = aPadding != nsIntMargin(0,0,0,0); bool doPartialDecode = !ImageComplete(); if (mSinglePixel && !doPadding && !doPartialDecode) { DoSingleColorFastPath(aContext, mSinglePixelColor, aFill); return; } gfxMatrix userSpaceToImageSpace = aUserSpaceToImageSpace; gfxRect sourceRect = userSpaceToImageSpace.Transform(aFill); gfxRect imageRect(0, 0, mSize.width + aPadding.LeftRight(), mSize.height + aPadding.TopBottom()); gfxRect subimage(aSubimage.x, aSubimage.y, aSubimage.width, aSubimage.height); gfxRect fill = aFill; NS_ASSERTION(!sourceRect.Intersect(subimage).IsEmpty(), "We must be allowed to sample *some* source pixels!"); bool doTile = !imageRect.Contains(sourceRect); SurfaceWithFormat surfaceResult = SurfaceForDrawing(doPadding, doPartialDecode, doTile, aPadding, userSpaceToImageSpace, fill, subimage, sourceRect, imageRect); if (surfaceResult.IsValid()) { gfxUtils::DrawPixelSnapped(aContext, surfaceResult.mDrawable, userSpaceToImageSpace, subimage, sourceRect, imageRect, fill, surfaceResult.mFormat, aFilter); } }
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; }