nsFontMetrics::nsFontMetrics(const nsFont& aFont, const Params& aParams, nsDeviceContext *aContext) : mFont(aFont) , mLanguage(aParams.language) , mDeviceContext(aContext) , mP2A(aContext->AppUnitsPerDevPixel()) , mOrientation(aParams.orientation) , mTextRunRTL(false) , mVertical(false) , mTextOrientation(0) { gfxFontStyle style(aFont.style, aFont.weight, aFont.stretch, gfxFloat(aFont.size) / mP2A, aParams.language, aParams.explicitLanguage, aFont.sizeAdjust, aFont.systemFont, mDeviceContext->IsPrinterSurface(), aFont.synthesis & NS_FONT_SYNTHESIS_WEIGHT, aFont.synthesis & NS_FONT_SYNTHESIS_STYLE, aFont.languageOverride); aFont.AddFontFeaturesToStyle(&style); gfxFloat devToCssSize = gfxFloat(mP2A) / gfxFloat(mDeviceContext->AppUnitsPerCSSPixel()); mFontGroup = gfxPlatform::GetPlatform()-> CreateFontGroup(aFont.fontlist, &style, aParams.textPerf, aParams.userFontSet, devToCssSize); }
nsresult nsFontMetrics::Init(const nsFont& aFont, nsIAtom* aLanguage, nsDeviceContext *aContext, gfxUserFontSet *aUserFontSet) { NS_ABORT_IF_FALSE(mP2A == -1, "already initialized"); mFont = aFont; mLanguage = aLanguage; mDeviceContext = aContext; mP2A = mDeviceContext->AppUnitsPerDevPixel(); gfxFontStyle style(aFont.style, aFont.weight, aFont.stretch, gfxFloat(aFont.size) / mP2A, aLanguage, aFont.sizeAdjust, aFont.systemFont, mDeviceContext->IsPrinterSurface(), aFont.featureSettings, aFont.languageOverride); mFontGroup = gfxPlatform::GetPlatform()-> CreateFontGroup(aFont.name, &style, aUserFontSet); if (mFontGroup->FontListLength() < 1) return NS_ERROR_UNEXPECTED; return NS_OK; }
nsresult nsFontMetrics::Init(const nsFont& aFont, nsIAtom* aLanguage, bool aExplicitLanguage, gfxFont::Orientation aOrientation, nsDeviceContext *aContext, gfxUserFontSet *aUserFontSet, gfxTextPerfMetrics *aTextPerf) { MOZ_ASSERT(mP2A == 0, "already initialized"); mFont = aFont; mLanguage = aLanguage; mOrientation = aOrientation; mDeviceContext = aContext; mP2A = mDeviceContext->AppUnitsPerDevPixel(); gfxFontStyle style(aFont.style, aFont.weight, aFont.stretch, gfxFloat(aFont.size) / mP2A, aLanguage, aExplicitLanguage, aFont.sizeAdjust, aFont.systemFont, mDeviceContext->IsPrinterSurface(), aFont.synthesis & NS_FONT_SYNTHESIS_WEIGHT, aFont.synthesis & NS_FONT_SYNTHESIS_STYLE, aFont.languageOverride); aFont.AddFontFeaturesToStyle(&style); mFontGroup = gfxPlatform::GetPlatform()-> CreateFontGroup(aFont.fontlist, &style, aTextPerf, aUserFontSet); return NS_OK; }
nsresult nsFontMetrics::Init(const nsFont& aFont, nsIAtom* aLanguage, nsDeviceContext *aContext, gfxUserFontSet *aUserFontSet, gfxTextPerfMetrics *aTextPerf) { NS_ABORT_IF_FALSE(mP2A == 0, "already initialized"); mFont = aFont; mLanguage = aLanguage; mDeviceContext = aContext; mP2A = mDeviceContext->AppUnitsPerDevPixel(); gfxFontStyle style(aFont.style, aFont.weight, aFont.stretch, gfxFloat(aFont.size) / mP2A, aLanguage, aFont.sizeAdjust, aFont.systemFont, mDeviceContext->IsPrinterSurface(), aFont.synthesis & NS_FONT_SYNTHESIS_WEIGHT, aFont.synthesis & NS_FONT_SYNTHESIS_STYLE, aFont.languageOverride); aFont.AddFontFeaturesToStyle(&style); mFontGroup = gfxPlatform::GetPlatform()-> CreateFontGroup(aFont.fontlist, &style, aUserFontSet); mFontGroup->SetTextPerfMetrics(aTextPerf); if (mFontGroup->FontListLength() < 1) return NS_ERROR_UNEXPECTED; return NS_OK; }
NS_IMETHODIMP nsThebesFontMetrics::Init(const nsFont& aFont, nsIAtom* aLangGroup, nsIDeviceContext *aContext, gfxUserFontSet *aUserFontSet) { mFont = aFont; mLangGroup = aLangGroup; mDeviceContext = (nsThebesDeviceContext*)aContext; mP2A = mDeviceContext->AppUnitsPerDevPixel(); mIsRightToLeft = PR_FALSE; mTextRunRTL = PR_FALSE; gfxFloat size = gfxFloat(aFont.size) / mP2A; nsCString langGroup; if (aLangGroup) { const char* lg; mLangGroup->GetUTF8String(&lg); langGroup.Assign(lg); } PRBool printerFont = mDeviceContext->IsPrinterSurface(); mFontStyle = new gfxFontStyle(aFont.style, aFont.weight, aFont.stretch, size, langGroup, aFont.sizeAdjust, aFont.systemFont, aFont.familyNameQuirks, printerFont); mFontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(aFont.name, mFontStyle, aUserFontSet); if (mFontGroup->FontListLength() < 1) return NS_ERROR_UNEXPECTED; return NS_OK; }
void gfxFontMissingGlyphs::DrawMissingGlyph(gfxContext *aContext, const gfxRect& aRect, uint32_t aChar, uint32_t aAppUnitsPerDevPixel) { 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.0 * 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); aContext->SetDeviceColor(currentColor); aContext->Translate(center); // We always want integer scaling, otherwise the "bitmap" glyphs will look // even uglier than usual when zoomed int32_t scale = std::max<int32_t>(1, nsDeviceContext::AppUnitsPerCSSPixel() / aAppUnitsPerDevPixel); aContext->Scale(gfxFloat(scale), gfxFloat(scale)); 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 gfxFloat left = -(MINIFONT_WIDTH + halfGap); DrawHexChar(aContext, gfxPoint(left, top), (aChar >> 12) & 0xF); DrawHexChar(aContext, gfxPoint(halfGap, top), (aChar >> 8) & 0xF); DrawHexChar(aContext, gfxPoint(left, halfGap), (aChar >> 4) & 0xF); DrawHexChar(aContext, gfxPoint(halfGap, halfGap), aChar & 0xF); } } else {
nsresult nsThebesImage::ThebesDrawTile(gfxContext *thebesContext, nsIDeviceContext* dx, const gfxPoint& offset, const gfxRect& targetRect, const nsIntRect& aSubimageRect, const PRInt32 xPadding, const PRInt32 yPadding) { NS_ASSERTION(xPadding >= 0 && yPadding >= 0, "negative padding"); if (targetRect.size.width <= 0.0 || targetRect.size.height <= 0.0) return NS_OK; // don't do anything if we have a transparent pixel source if (mSinglePixel && mSinglePixelColor.a == 0.0) return NS_OK; PRBool doSnap = !(thebesContext->CurrentMatrix().HasNonTranslation()); PRBool hasPadding = ((xPadding != 0) || (yPadding != 0)); gfxImageSurface::gfxImageFormat format = mFormat; gfxPoint tmpOffset = offset; if (mSinglePixel && !hasPadding) { thebesContext->SetDeviceColor(mSinglePixelColor); } else { nsRefPtr<gfxASurface> surface; PRInt32 width, height; if (hasPadding) { /* Ugh we have padding; create a temporary surface that's the size of the surface + pad area, * and render the image into it first. Then we'll tile that surface. */ width = mWidth + xPadding; height = mHeight + yPadding; // Reject over-wide or over-tall images. if (!AllowedImageSize(width, height)) return NS_ERROR_FAILURE; format = gfxASurface::ImageFormatARGB32; surface = gfxPlatform::GetPlatform()->CreateOffscreenSurface( gfxIntSize(width, height), format); if (!surface || surface->CairoStatus()) { return NS_ERROR_OUT_OF_MEMORY; } gfxContext tmpContext(surface); if (mSinglePixel) { tmpContext.SetDeviceColor(mSinglePixelColor); } else { tmpContext.SetSource(ThebesSurface()); } tmpContext.SetOperator(gfxContext::OPERATOR_SOURCE); tmpContext.Rectangle(gfxRect(0, 0, mWidth, mHeight)); tmpContext.Fill(); } else { width = mWidth; height = mHeight; surface = ThebesSurface(); } // Scale factor to account for CSS pixels; note that the offset (and // therefore p0) is in device pixels, while the width and height are in // CSS pixels. gfxFloat scale = gfxFloat(dx->AppUnitsPerDevPixel()) / gfxFloat(nsIDeviceContext::AppUnitsPerCSSPixel()); if ((aSubimageRect.width < width || aSubimageRect.height < height) && (thebesContext->CurrentMatrix().HasNonTranslation() || scale != 1.0)) { // Some of the source image should not be drawn, and we're going // to be doing more than just translation, so we might accidentally // sample the non-drawn pixels. Avoid that by creating a // temporary image representing the portion that will be drawn, // with built-in padding since we can't use EXTEND_PAD and // EXTEND_REPEAT at the same time for different axes. PRInt32 padX = aSubimageRect.width < width ? 1 : 0; PRInt32 padY = aSubimageRect.height < height ? 1 : 0; PRInt32 tileWidth = PR_MIN(aSubimageRect.width, width); PRInt32 tileHeight = PR_MIN(aSubimageRect.height, height); // This tmpSurface will contain a snapshot of the repeated // tile image at (aSubimageRect.x, aSubimageRect.y, // tileWidth, tileHeight), with padX padding added to the left // and right sides and padY padding added to the top and bottom // sides. nsRefPtr<gfxASurface> tmpSurface; tmpSurface = gfxPlatform::GetPlatform()->CreateOffscreenSurface( gfxIntSize(tileWidth + 2*padX, tileHeight + 2*padY), format); if (!tmpSurface || tmpSurface->CairoStatus()) { return NS_ERROR_OUT_OF_MEMORY; } gfxContext tmpContext(tmpSurface); tmpContext.SetOperator(gfxContext::OPERATOR_SOURCE); gfxPattern pat(surface); pat.SetExtend(gfxPattern::EXTEND_REPEAT); // Copy the needed portion of the source image to the temporary // surface. We also copy over horizontal and/or vertical padding // strips one pixel wide, plus the corner pixels if necessary. // So in the most general case the temporary surface ends up // looking like // P P P ... P P P // P X X ... X X P // P X X ... X X P // ............... // P X X ... X X P // P X X ... X X P // P P P ... P P P // Where each P pixel has the color of its nearest source X // pixel. We implement this as a loop over all nine possible // areas, [padding, body, padding] x [padding, body, padding]. // Note that we will not need padding on both axes unless // we are painting just a single tile, in which case this // will hardly ever get called since nsCSSRendering converts // the single-tile case to nsLayoutUtils::DrawImage. But this // could be called on other paths (XUL trees?) and it's simpler // and clearer to do it the general way. PRInt32 destY = 0; for (PRInt32 y = -1; y <= 1; ++y) { PRInt32 stripHeight = y == 0 ? tileHeight : padY; if (stripHeight == 0) continue; PRInt32 srcY = y == 1 ? aSubimageRect.YMost() - padY : aSubimageRect.y; PRInt32 destX = 0; for (PRInt32 x = -1; x <= 1; ++x) { PRInt32 stripWidth = x == 0 ? tileWidth : padX; if (stripWidth == 0) continue; PRInt32 srcX = x == 1 ? aSubimageRect.XMost() - padX : aSubimageRect.x; gfxMatrix patMat; patMat.Translate(gfxPoint(srcX - destX, srcY - destY)); pat.SetMatrix(patMat); tmpContext.SetPattern(&pat); tmpContext.Rectangle(gfxRect(destX, destY, stripWidth, stripHeight)); tmpContext.Fill(); tmpContext.NewPath(); destX += stripWidth; } destY += stripHeight; } // tmpOffset was the top-left of the old tile image. Make it // the top-left of the new tile image. Note that tmpOffset is // in destination coordinate space so we have to scale our // CSS pixels. tmpOffset += gfxPoint(aSubimageRect.x - padX, aSubimageRect.y - padY)/scale; surface = tmpSurface; } gfxMatrix patMat; gfxPoint p0; p0.x = - floor(tmpOffset.x + 0.5); p0.y = - floor(tmpOffset.y + 0.5); patMat.Scale(scale, scale); patMat.Translate(p0); gfxPattern pat(surface); pat.SetExtend(gfxPattern::EXTEND_REPEAT); pat.SetMatrix(patMat); #ifndef XP_MACOSX if (scale < 1.0) { // See bug 324698. This is a workaround. See comments // by the earlier SetFilter call. pat.SetFilter(0); } #endif thebesContext->SetPattern(&pat); } gfxContext::GraphicsOperator op = thebesContext->CurrentOperator(); if (op == gfxContext::OPERATOR_OVER && format == gfxASurface::ImageFormatRGB24) thebesContext->SetOperator(gfxContext::OPERATOR_SOURCE); thebesContext->NewPath(); thebesContext->Rectangle(targetRect, doSnap); thebesContext->Fill(); thebesContext->SetOperator(op); thebesContext->SetDeviceColor(gfxRGBA(0,0,0,0)); return NS_OK; }