Backout of 375141 - appears to be causing qm-winxp01 red.

This commit is contained in:
tor@cs.brown.edu 2007-04-17 20:54:53 -07:00
parent 7745a13efc
commit d29f8f426a
2 changed files with 340 additions and 300 deletions

View File

@ -53,12 +53,7 @@
#include "nsDOMError.h"
#include "gfxContext.h"
#include "gfxMatrix.h"
#include "gfxPlatform.h"
// XXX: This initial straightforward conversion from accessing cairo
// directly to Thebes doesn't handle clusters. Pretty much all code
// that measures or draws single characters (textPath code and some
// DOM accessors) will need to be reworked.
#include "cairo.h"
//----------------------------------------------------------------------
// Implementation
@ -122,35 +117,6 @@ nsSVGGlyphFrame::DidSetStyleContext()
{
nsSVGGlyphFrameBase::DidSetStyleContext();
const nsStyleFont* fontData = GetStyleFont();
nsFont font = fontData->mFont;
// Since SVG has its own scaling, we really don't want
// fonts in SVG to respond to the browser's "TextZoom"
// (Ctrl++,Ctrl+-)
nsPresContext *presContext = PresContext();
float textZoom = presContext->TextZoom();
double size = presContext->AppUnitsToDevPixels(fontData->mSize) / textZoom;
nsCAutoString langGroup;
nsIAtom *langGroupAtom = presContext->GetLangGroup();
if (langGroupAtom) {
const char* lg;
langGroupAtom->GetUTF8String(&lg);
langGroup.Assign(lg);
}
// XXX decorations are ignored by gfxFontStyle - still need to implement
mFontStyle = new gfxFontStyle(font.style, font.variant,
font.weight, font.decorations,
size, langGroup, font.sizeAdjust,
font.systemFont, font.familyNameQuirks);
if (mFontStyle) {
mFontGroup =
gfxPlatform::GetPlatform()->CreateFontGroup(font.name, mFontStyle);
}
return UpdateGraphic();
}
@ -213,43 +179,23 @@ nsSVGGlyphFrame::GetType() const
// nsISVGChildFrame methods
void
nsSVGGlyphFrame::LoopCharacters(gfxContext *aCtx, const nsString &aText,
nsSVGGlyphFrame::LoopCharacters(cairo_t *aCtx, const nsAString &aText,
const nsSVGCharacterPosition *aCP,
FillOrStroke aFillOrStroke)
void (*aFunc)(cairo_t *cr, const char *utf8))
{
nsAutoPtr<gfxTextRun> textRun(GetTextRun(aCtx, aText));
if (!textRun)
return;
if (!aCP) {
if (aFillOrStroke == STROKE) {
textRun->DrawToPath(aCtx, mPosition, 0, aText.Length(), nsnull, nsnull);
} else {
textRun->Draw(aCtx, mPosition, 0, aText.Length(),
nsnull, nsnull, nsnull);
}
aFunc(aCtx, NS_ConvertUTF16toUTF8(aText).get());
} else {
for (PRUint32 i = 0; i < aText.Length(); i++) {
/* character actually on the path? */
if (aCP[i].draw == PR_FALSE)
continue;
gfxMatrix matrix = aCtx->CurrentMatrix();
gfxMatrix rot;
rot.Rotate(aCP[i].angle);
aCtx->Multiply(rot);
rot.Invert();
gfxPoint pt = rot.Transform(aCP[i].pos);
if (aFillOrStroke == STROKE) {
textRun->DrawToPath(aCtx, pt, i, 1, nsnull, nsnull);
} else {
textRun->Draw(aCtx, pt, i, 1, nsnull, nsnull, nsnull);
}
aCtx->SetMatrix(matrix);
cairo_matrix_t matrix;
cairo_get_matrix(aCtx, &matrix);
cairo_move_to(aCtx, aCP[i].x, aCP[i].y);
cairo_rotate(aCtx, aCP[i].angle);
aFunc(aCtx, NS_ConvertUTF16toUTF8(Substring(aText, i, 1)).get());
cairo_set_matrix(aCtx, &matrix);
}
}
}
@ -268,62 +214,70 @@ nsSVGGlyphFrame::PaintSVG(nsSVGRenderState *aContext, nsRect *aDirtyRect)
nsAutoArrayPtr<nsSVGCharacterPosition> cp;
gfxContext *gfx = aContext->GetGfxContext();
cairo_t *ctx = gfx->GetCairo();
SelectFont(gfx);
nsresult rv = GetCharacterPosition(gfx, text, getter_Transfers(cp));
gfxMatrix matrix;
cairo_matrix_t matrix;
PRUint16 renderMode = aContext->GetRenderMode();
if (renderMode == nsSVGRenderState::NORMAL) {
/* save/pop the state so we don't screw up the xform */
gfx->Save();
cairo_save(ctx);
}
else {
matrix = gfx->CurrentMatrix();
cairo_get_matrix(ctx, &matrix);
}
rv = GetGlobalTransform(gfx);
if (NS_FAILED(rv)) {
if (renderMode == nsSVGRenderState::NORMAL)
gfx->Restore();
cairo_restore(ctx);
return rv;
}
if (!cp)
cairo_move_to(ctx, mX, mY);
if (renderMode != nsSVGRenderState::NORMAL) {
if (GetClipRule() == NS_STYLE_FILL_RULE_EVENODD)
gfx->SetFillRule(gfxContext::FILL_RULE_EVEN_ODD);
cairo_set_fill_rule(ctx, CAIRO_FILL_RULE_EVEN_ODD);
else
gfx->SetFillRule(gfxContext::FILL_RULE_WINDING);
cairo_set_fill_rule(ctx, CAIRO_FILL_RULE_WINDING);
if (renderMode == nsSVGRenderState::CLIP_MASK) {
gfx->SetAntialiasMode(gfxContext::MODE_ALIASED);
gfx->SetColor(gfxRGBA(1.0f, 1.0f, 1.0f, 1.0f));
LoopCharacters(gfx, text, cp, FILL);
cairo_set_antialias(ctx, CAIRO_ANTIALIAS_NONE);
cairo_set_source_rgba(ctx, 1.0f, 1.0f, 1.0f, 1.0f);
LoopCharacters(ctx, text, cp, cairo_show_text);
} else {
LoopCharacters(gfx, text, cp, STROKE);
LoopCharacters(ctx, text, cp, cairo_text_path);
}
gfx->SetMatrix(matrix);
cairo_set_matrix(ctx, &matrix);
return NS_OK;
}
void *closure;
if (HasFill() && NS_SUCCEEDED(SetupCairoFill(gfx, &closure))) {
LoopCharacters(gfx, text, cp, FILL);
LoopCharacters(ctx, text, cp, cairo_show_text);
CleanupCairoFill(gfx, closure);
}
if (HasStroke() && NS_SUCCEEDED(SetupCairoStroke(gfx, &closure))) {
gfx->NewPath();
LoopCharacters(gfx, text, cp, STROKE);
gfx->Stroke();
cairo_new_path(ctx);
if (!cp)
cairo_move_to(ctx, mX, mY);
LoopCharacters(ctx, text, cp, cairo_text_path);
cairo_stroke(ctx);
CleanupCairoStroke(gfx, closure);
gfx->NewPath();
cairo_new_path(ctx);
}
gfx->Restore();
cairo_restore(ctx);
return NS_OK;
}
@ -408,64 +362,60 @@ nsSVGGlyphFrame::UpdateCoveredRegion()
nsSVGAutoGlyphHelperContext ctx(this, text, getter_Transfers(cp));
gfxContext *gfx = ctx.GetContext();
gfxTextRun *textRun = ctx.GetTextRun();
if (!gfx || !textRun)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = GetGlobalTransform(gfx);
nsresult rv = GetGlobalTransform(ctx);
NS_ENSURE_SUCCESS(rv, rv);
if (!cp) {
cairo_move_to(ctx, mX, mY);
if (hasStroke) {
textRun->DrawToPath(gfx, mPosition, 0, text.Length(), nsnull, nsnull);
cairo_text_path(ctx, NS_ConvertUTF16toUTF8(text).get());
} else {
gfxTextRun::Metrics metrics =
textRun->MeasureText(0, text.Length(), PR_FALSE, nsnull);
gfx->Rectangle(metrics.mBoundingBox + mPosition);
cairo_text_extents_t extent;
cairo_text_extents(ctx,
NS_ConvertUTF16toUTF8(text).get(),
&extent);
cairo_rectangle(ctx, mX + extent.x_bearing, mY + extent.y_bearing,
extent.width, extent.height);
}
} else {
cairo_matrix_t matrix;
for (PRUint32 i=0; i<text.Length(); i++) {
/* character actually on the path? */
if (cp[i].draw == PR_FALSE)
continue;
gfxMatrix matrix = gfx->CurrentMatrix();
cairo_get_matrix(ctx, &matrix);
cairo_move_to(ctx, cp[i].x, cp[i].y);
cairo_rotate(ctx, cp[i].angle);
if (hasStroke) {
gfxMatrix rot;
rot.Rotate(cp[i].angle);
gfx->Multiply(rot);
rot.Invert();
gfxPoint pt = rot.Transform(cp[i].pos);
textRun->DrawToPath(gfx, pt, i, 1, nsnull, nsnull);
cairo_text_path(ctx, NS_ConvertUTF16toUTF8(Substring(text, i, 1)).get());
} else {
gfx->MoveTo(cp[i].pos);
gfx->Rotate(cp[i].angle);
gfxTextRun::Metrics metrics =
textRun->MeasureText(i, 1, PR_FALSE, nsnull);
gfx->Rectangle(metrics.mBoundingBox + gfx->CurrentPoint());
cairo_text_extents_t extent;
cairo_text_extents(ctx,
NS_ConvertUTF16toUTF8(Substring(text, i, 1)).get(),
&extent);
cairo_rel_move_to(ctx, extent.x_bearing, extent.y_bearing);
cairo_rel_line_to(ctx, extent.width, 0);
cairo_rel_line_to(ctx, 0, extent.height);
cairo_rel_line_to(ctx, -extent.width, 0);
cairo_close_path(ctx);
}
gfx->SetMatrix(matrix);
cairo_set_matrix(ctx, &matrix);
}
}
gfxRect extent;
double xmin, ymin, xmax, ymax;
if (hasStroke) {
SetupCairoStrokeGeometry(gfx);
extent = gfx->GetUserStrokeExtent();
extent = gfx->UserToDevice(extent);
SetupCairoStrokeGeometry(ctx);
cairo_stroke_extents(ctx, &xmin, &ymin, &xmax, &ymax);
nsSVGUtils::UserToDeviceBBox(ctx, &xmin, &ymin, &xmax, &ymax);
} else {
gfx->IdentityMatrix();
extent = gfx->GetUserFillExtent();
cairo_identity_matrix(ctx);
cairo_fill_extents(ctx, &xmin, &ymin, &xmax, &ymax);
}
mRect = nsSVGUtils::ToBoundingPixelRect(extent);
mRect = nsSVGUtils::ToBoundingPixelRect(xmin, ymin, xmax, ymax);
return NS_OK;
}
@ -523,18 +473,21 @@ nsSVGGlyphFrame::GetBBox(nsIDOMSVGRect **_retval)
nsSVGAutoGlyphHelperContext ctx(this, text, getter_Transfers(cp));
gfxContext *gfx = ctx.GetContext();
if (!gfx)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = GetGlobalTransform(gfx);
nsresult rv = GetGlobalTransform(ctx);
NS_ENSURE_SUCCESS(rv, rv);
LoopCharacters(gfx, text, cp, STROKE);
gfx->IdentityMatrix();
gfxRect rect = gfx->GetUserFillExtent();
if (!cp)
cairo_move_to(ctx, mX, mY);
return NS_NewSVGRect(_retval, rect);
LoopCharacters(ctx, text, cp, cairo_text_path);
cairo_identity_matrix(ctx);
double xmin, ymin, xmax, ymax;
cairo_fill_extents(ctx, &xmin, &ymin, &xmax, &ymax);
return NS_NewSVGRect(_retval, xmin, ymin, xmax - xmin, ymax - ymin);
}
//----------------------------------------------------------------------
@ -587,9 +540,11 @@ nsSVGGlyphFrame::GetCharacterData(nsAString & aCharacterData)
nsresult
nsSVGGlyphFrame::GetCharacterPosition(gfxContext *aContext,
const nsString &aText,
const nsAString &aText,
nsSVGCharacterPosition **aCharacterPosition)
{
cairo_t *ctx = aContext->GetCairo();
*aCharacterPosition = nsnull;
NS_ASSERTION(!aText.IsEmpty(), "no text");
@ -610,18 +565,20 @@ nsSVGGlyphFrame::GetCharacterPosition(gfxContext *aContext,
float length = data->GetLength();
PRUint32 strLength = aText.Length();
nsAutoPtr<gfxTextRun> textRun(GetTextRun(aContext, aText));
if (!textRun)
return NS_ERROR_OUT_OF_MEMORY;
nsSVGCharacterPosition *cp = new nsSVGCharacterPosition[strLength];
for (PRUint32 k = 0; k < strLength; k++)
cp[k].draw = PR_FALSE;
float x = mPosition.x;
float x = mX;
for (PRUint32 i = 0; i < strLength; i++) {
float halfAdvance = textRun->GetAdvanceWidth(i, 1, nsnull) / 2.0;
cairo_text_extents_t extent;
cairo_text_extents(ctx,
NS_ConvertUTF16toUTF8(Substring(aText, i, 1)).get(),
&extent);
float halfAdvance = extent.x_advance / 2.0;
/* have we run off the end of the path? */
if (x + halfAdvance > length)
@ -634,10 +591,10 @@ nsSVGGlyphFrame::GetCharacterPosition(gfxContext *aContext,
// add y (normal)
// add rotation
// move point back along tangent
gfxPoint pt = data->FindPoint(gfxPoint(x + halfAdvance, mPosition.y),
gfxPoint pt = data->FindPoint(gfxPoint(x + halfAdvance, mY),
&(cp[i].angle));
cp[i].pos =
pt - gfxPoint(cos(cp[i].angle), sin(cp[i].angle)) * halfAdvance;
cp[i].x = pt.x - cos(cp[i].angle) * halfAdvance;
cp[i].y = pt.y - sin(cp[i].angle) * halfAdvance;
}
x += 2 * halfAdvance;
}
@ -794,7 +751,8 @@ nsSVGGlyphFrame::GetHighlight(PRUint32 *charnum, PRUint32 *nchars,
NS_IMETHODIMP_(void)
nsSVGGlyphFrame::SetGlyphPosition(float x, float y)
{
mPosition.MoveTo(x, y);
mX = x;
mY = y;
UpdateGeometry(PR_TRUE, PR_FALSE);
}
@ -810,26 +768,35 @@ nsSVGGlyphFrame::GetStartPositionOfChar(PRUint32 charnum, nsIDOMSVGPoint **_retv
nsSVGAutoGlyphHelperContext ctx(this, text, getter_Transfers(cp));
gfxPoint pt;
float x, y;
if (cp) {
if (cp[charnum].draw == PR_FALSE) {
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
pt = cp[charnum].pos;
x = cp[charnum].x;
y = cp[charnum].y;
} else {
pt = mPosition;
x = mX;
y = mY;
if (charnum > 0) {
gfxTextRun *textRun = ctx.GetTextRun();
if (!textRun)
return NS_ERROR_OUT_OF_MEMORY;
pt.x += textRun->GetAdvanceWidth(0, charnum, nsnull);
cairo_text_extents_t extent;
cairo_text_extents(ctx,
NS_ConvertUTF16toUTF8(Substring(text,
0,
charnum)).get(),
&extent);
x += extent.x_advance;
y += extent.y_advance;
}
}
return NS_NewSVGPoint(_retval, pt.x, pt.y);
return NS_NewSVGPoint(_retval, x, y);
}
NS_IMETHODIMP
@ -841,29 +808,33 @@ nsSVGGlyphFrame::GetEndPositionOfChar(PRUint32 charnum, nsIDOMSVGPoint **_retval
GetCharacterData(text);
nsAutoArrayPtr<nsSVGCharacterPosition> cp;
nsSVGAutoGlyphHelperContext ctx(this, text, getter_Transfers(cp));
gfxTextRun *textRun = ctx.GetTextRun();
if (!textRun)
return NS_ERROR_OUT_OF_MEMORY;
cairo_text_extents_t extent;
if (cp) {
if (cp[charnum].draw == PR_FALSE) {
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
float advance = textRun->GetAdvanceWidth(charnum, 1, nsnull);
cairo_text_extents(ctx,
NS_ConvertUTF16toUTF8(Substring(text, charnum, 1)).get(),
&extent);
return NS_NewSVGPoint(_retval,
cp[charnum].pos.x + advance * cos(cp[charnum].angle),
cp[charnum].pos.y + advance * sin(cp[charnum].angle));
float s = sin(cp[charnum].angle);
float c = cos(cp[charnum].angle);
return NS_NewSVGPoint(_retval,
cp[charnum].x + extent.x_advance * c - extent.y_advance * s,
cp[charnum].y + extent.y_advance * c + extent.x_advance * s);
}
return NS_NewSVGPoint(_retval,
mPosition.x + textRun->GetAdvanceWidth(0,
charnum + 1,
nsnull),
mPosition.y);
cairo_text_extents(ctx,
NS_ConvertUTF16toUTF8(Substring(text, 0, charnum + 1)).get(),
&extent);
return NS_NewSVGPoint(_retval, mX + extent.x_advance, mY + extent.y_advance);
}
NS_IMETHODIMP
@ -877,47 +848,60 @@ nsSVGGlyphFrame::GetExtentOfChar(PRUint32 charnum, nsIDOMSVGRect **_retval)
nsAutoArrayPtr<nsSVGCharacterPosition> cp;
nsSVGAutoGlyphHelperContext ctx(this, text, getter_Transfers(cp));
gfxTextRun *textRun = ctx.GetTextRun();
if (!textRun)
return NS_ERROR_OUT_OF_MEMORY;
gfxTextRun::Metrics metrics =
textRun->MeasureText(charnum, 1, PR_FALSE, nsnull);
cairo_text_extents_t extent;
cairo_text_extents(ctx,
NS_ConvertUTF16toUTF8(Substring(text, charnum, 1)).get(),
&extent);
if (cp) {
if (cp[charnum].draw == PR_FALSE) {
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
gfxContext *gfx = ctx.GetContext();
if (!gfx)
return NS_ERROR_OUT_OF_MEMORY;
cairo_matrix_t matrix;
cairo_get_matrix(ctx, &matrix);
cairo_move_to(ctx, cp[charnum].x, cp[charnum].y);
cairo_rotate(ctx, cp[charnum].angle);
gfxMatrix matrix = gfx->CurrentMatrix();
cairo_rel_move_to(ctx, extent.x_bearing, extent.y_bearing);
cairo_rel_line_to(ctx, extent.width, 0);
cairo_rel_line_to(ctx, 0, extent.height);
cairo_rel_line_to(ctx, -extent.width, 0);
cairo_close_path(ctx);
cairo_identity_matrix(ctx);
gfx->MoveTo(cp[charnum].pos);
gfx->Rotate(cp[charnum].angle);
double xmin, ymin, xmax, ymax;
gfx->Rectangle(metrics.mBoundingBox + gfx->CurrentPoint());
cairo_fill_extents(ctx, &xmin, &ymin, &xmax, &ymax);
gfx->IdentityMatrix();
cairo_set_matrix(ctx, &matrix);
gfxRect rect = gfx->GetUserFillExtent();
gfx->SetMatrix(matrix);
return NS_NewSVGRect(_retval, rect);
return NS_NewSVGRect(_retval, xmin, ymin, xmax - xmin, ymax - ymin);
}
gfxPoint pt = mPosition;
float x = mX;
float y = mY;
x += extent.x_bearing;
y += extent.y_bearing;
cairo_text_extents_t precedingExtent;
if (charnum > 0) {
// add the space taken up by the text which comes before charnum
// to the position of the charnum character
pt.x += textRun->GetAdvanceWidth(0, charnum, nsnull);
cairo_text_extents(ctx,
NS_ConvertUTF16toUTF8(Substring(text,
0,
charnum)).get(),
&precedingExtent);
x += precedingExtent.x_advance;
y += precedingExtent.y_advance;
}
return NS_NewSVGRect(_retval, metrics.mBoundingBox + pt);
return NS_NewSVGRect(_retval, x, y, extent.width, extent.height);
}
NS_IMETHODIMP
@ -948,38 +932,32 @@ NS_IMETHODIMP_(float)
nsSVGGlyphFrame::GetBaselineOffset(PRUint16 baselineIdentifier)
{
float _retval;
cairo_font_extents_t extents;
nsAutoString text;
GetCharacterData(text);
nsSVGAutoGlyphHelperContext ctx(this);
nsSVGAutoGlyphHelperContext ctx(this, text);
gfxTextRun *textRun = ctx.GetTextRun();
if (!textRun)
return 0.0f;
gfxTextRun::Metrics metrics =
textRun->MeasureText(0, text.Length(), PR_FALSE, nsnull);
cairo_font_extents(ctx, &extents);
switch (baselineIdentifier) {
case BASELINE_HANGING:
// not really right, but the best we can do with the information provided
// FALLTHROUGH
case BASELINE_TEXT_BEFORE_EDGE:
_retval = -metrics.mAscent;
_retval = -extents.ascent;
break;
case BASELINE_TEXT_AFTER_EDGE:
_retval = metrics.mDescent;
_retval = extents.descent;
break;
case BASELINE_CENTRAL:
case BASELINE_MIDDLE:
_retval = - (metrics.mAscent - metrics.mDescent) / 2.0;
_retval = - (extents.ascent - extents.descent) / 2.0;
break;
case BASELINE_ALPHABETIC:
default:
_retval = 0.0;
break;
}
return _retval;
}
@ -991,12 +969,14 @@ nsSVGGlyphFrame::GetAdvance()
return 0.0f;
}
nsSVGAutoGlyphHelperContext ctx(this, text);
gfxTextRun *textRun = ctx.GetTextRun();
if (!textRun)
return 0.0f;
nsSVGAutoGlyphHelperContext ctx(this);
return textRun->GetAdvanceWidth(0, text.Length(), nsnull);
cairo_text_extents_t extents;
cairo_text_extents(ctx,
NS_ConvertUTF16toUTF8(text).get(),
&extents);
return extents.x_advance;
}
NS_IMETHODIMP_(nsSVGTextPathFrame*)
@ -1124,7 +1104,19 @@ nsSVGGlyphFrame::GetNumberOfChars()
NS_IMETHODIMP_(float)
nsSVGGlyphFrame::GetComputedTextLength()
{
return GetAdvance();
nsAutoString text;
if (!GetCharacterData(text)) {
return 0.0f;
}
nsSVGAutoGlyphHelperContext ctx(this);
cairo_text_extents_t extent;
cairo_text_extents(ctx,
NS_ConvertUTF16toUTF8(text).get(),
&extent);
return fabs(extent.x_advance) + fabs(extent.y_advance);
}
NS_IMETHODIMP_(float)
@ -1133,12 +1125,14 @@ nsSVGGlyphFrame::GetSubStringLength(PRUint32 charnum, PRUint32 fragmentChars)
nsAutoString text;
GetCharacterData(text);
nsSVGAutoGlyphHelperContext ctx(this, text);
gfxTextRun *textRun = ctx.GetTextRun();
if (!textRun)
return 0.0f;
nsSVGAutoGlyphHelperContext ctx(this);
return textRun->GetAdvanceWidth(charnum, fragmentChars, nsnull);
cairo_text_extents_t extent;
cairo_text_extents(ctx,
NS_ConvertUTF16toUTF8(Substring(text, charnum, fragmentChars)).get(),
&extent);
return fabs(extent.x_advance) + fabs(extent.y_advance);
}
NS_IMETHODIMP_(PRInt32)
@ -1155,48 +1149,55 @@ nsSVGGlyphFrame::GetCharNumAtPosition(nsIDOMSVGPoint *point)
nsSVGAutoGlyphHelperContext ctx(this, text, getter_Transfers(cp));
gfxPoint pt;
float x, y;
if (!cp) {
pt = mPosition;
x = mX;
y = mY;
}
gfxContext *gfx = ctx.GetContext();
gfxTextRun *textRun = ctx.GetTextRun();
if (!gfx || !textRun)
return NS_ERROR_OUT_OF_MEMORY;
for (PRUint32 charnum = 0; charnum < text.Length(); charnum++) {
/* character actually on the path? */
if (cp && cp[charnum].draw == PR_FALSE)
continue;
gfxMatrix matrix = gfx->CurrentMatrix();
gfx->NewPath();
cairo_matrix_t matrix;
cairo_get_matrix(ctx, &matrix);
cairo_new_path(ctx);
if (cp) {
gfx->MoveTo(cp[charnum].pos);
gfx->Rotate(cp[charnum].angle);
cairo_move_to(ctx, cp[charnum].x, cp[charnum].y);
cairo_rotate(ctx, cp[charnum].angle);
} else {
if (charnum > 0) {
gfx->MoveTo(pt + gfxPoint(textRun->GetAdvanceWidth(0, charnum, nsnull),
0));
cairo_text_extents_t extent;
cairo_text_extents(ctx,
NS_ConvertUTF16toUTF8(Substring(text,
0,
charnum)).get(),
&extent);
cairo_move_to(ctx, x + extent.x_advance, y + extent.y_advance);
} else {
gfx->MoveTo(pt);
cairo_move_to(ctx, x, y);
}
}
cairo_text_extents_t extent;
cairo_text_extents(ctx,
NS_ConvertUTF16toUTF8(Substring(text, charnum, 1)).get(),
&extent);
gfxTextRun::Metrics metrics =
textRun->MeasureText(charnum, 1, PR_FALSE, nsnull);
cairo_rel_move_to(ctx, extent.x_bearing, extent.y_bearing);
cairo_rel_line_to(ctx, extent.width, 0);
cairo_rel_line_to(ctx, 0, extent.height);
cairo_rel_line_to(ctx, -extent.width, 0);
cairo_close_path(ctx);
gfx->Rectangle(metrics.mBoundingBox + gfx->CurrentPoint());
gfx->IdentityMatrix();
if (gfx->PointInFill(gfxPoint(xPos, yPos))) {
gfx->SetMatrix(matrix);
cairo_identity_matrix(ctx);
if (cairo_in_fill(ctx, xPos, yPos)) {
return charnum;
}
gfx->SetMatrix(matrix);
cairo_set_matrix(ctx, &matrix);
}
return -1;
}
@ -1236,6 +1237,68 @@ nsSVGGlyphFrame::SetWhitespaceHandling(PRUint8 aWhitespaceHandling)
//----------------------------------------------------------------------
//
void nsSVGGlyphFrame::SelectFont(gfxContext *aContext)
{
cairo_t *ctx = aContext->GetCairo();
const nsStyleFont* fontData = GetStyleFont();
nsFont font = fontData->mFont;
// XXX eventually we will have to treat decorations separately from
// fonts, because they can have a different color than the current
// glyph.
NS_ASSERTION(mParent, "no parent");
nsStyleContext *parentContext = mParent->GetStyleContext();
NS_ASSERTION(parentContext, "no style context on parent");
PRUint8 styleDecorations =
parentContext->GetStyleTextReset()->mTextDecoration;
if (styleDecorations & NS_STYLE_TEXT_DECORATION_UNDERLINE)
font.decorations |= NS_FONT_DECORATION_UNDERLINE;
if (styleDecorations & NS_STYLE_TEXT_DECORATION_OVERLINE)
font.decorations |= NS_FONT_DECORATION_OVERLINE;
if (styleDecorations & NS_STYLE_TEXT_DECORATION_LINE_THROUGH)
font.decorations |= NS_FONT_DECORATION_LINE_THROUGH;
cairo_font_slant_t slant;
cairo_font_weight_t weight = CAIRO_FONT_WEIGHT_NORMAL;
switch (font.style) {
case NS_FONT_STYLE_NORMAL:
slant = CAIRO_FONT_SLANT_NORMAL;
break;
case NS_FONT_STYLE_ITALIC:
slant = CAIRO_FONT_SLANT_ITALIC;
break;
case NS_FONT_STYLE_OBLIQUE:
slant = CAIRO_FONT_SLANT_OBLIQUE;
break;
}
if (font.weight % 100 == 0) {
if (font.weight >= 600)
weight = CAIRO_FONT_WEIGHT_BOLD;
} else if (font.weight % 100 < 50) {
weight = CAIRO_FONT_WEIGHT_BOLD;
}
nsAutoString family;
font.GetFirstFamily(family);
cairo_select_font_face(ctx,
NS_ConvertUTF16toUTF8(family).get(),
slant,
weight);
// Since SVG has its own scaling, we really don't want
// fonts in SVG to respond to the browser's "TextZoom"
// (Ctrl++,Ctrl+-)
nsPresContext *presContext = PresContext();
float textZoom = presContext->TextZoom();
cairo_set_font_size(ctx, presContext->AppUnitsToDevPixels(fontData->mSize) / textZoom);
}
void nsSVGGlyphFrame::UpdateGeometry(PRBool bRedraw,
PRBool suppressInvalidation)
{
@ -1280,47 +1343,52 @@ nsSVGGlyphFrame::ContainsPoint(float x, float y)
nsAutoArrayPtr<nsSVGCharacterPosition> cp;
nsSVGAutoGlyphHelperContext ctx(this, text, getter_Transfers(cp));
gfxContext *gfx = ctx.GetContext();
gfxTextRun *textRun = ctx.GetTextRun();
if (!gfx || !textRun)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = GetGlobalTransform(gfx);
nsresult rv = GetGlobalTransform(ctx);
NS_ENSURE_SUCCESS(rv, PR_FALSE);
gfxPoint pt;
float xx = 0, yy = 0;
if (!cp) {
pt = mPosition;
xx = mX;
yy = mY;
}
cairo_matrix_t matrix;
for (PRUint32 i = 0; i < text.Length(); i++) {
/* character actually on the path? */
if (cp && cp[i].draw == PR_FALSE)
continue;
gfxMatrix matrix = gfx->CurrentMatrix();
cairo_get_matrix(ctx, &matrix);
if (cp) {
gfx->MoveTo(cp[i].pos);
gfx->Rotate(cp[i].angle);
cairo_move_to(ctx, cp[i].x, cp[i].y);
cairo_rotate(ctx, cp[i].angle);
} else {
gfx->MoveTo(pt);
cairo_move_to(ctx, xx, yy);
}
gfxTextRun::Metrics metrics =
textRun->MeasureText(i, 1, PR_FALSE, nsnull);
cairo_text_extents_t extent;
cairo_text_extents(ctx,
NS_ConvertUTF16toUTF8(Substring(text, i, 1)).get(),
&extent);
cairo_rel_move_to(ctx, extent.x_bearing, extent.y_bearing);
cairo_rel_line_to(ctx, extent.width, 0);
cairo_rel_line_to(ctx, 0, extent.height);
cairo_rel_line_to(ctx, -extent.width, 0);
cairo_close_path(ctx);
gfx->Rectangle(metrics.mBoundingBox + gfx->CurrentPoint());
gfx->SetMatrix(matrix);
cairo_set_matrix(ctx, &matrix);
if (!cp) {
pt.x += metrics.mAdvanceWidth;
xx += extent.x_advance;
yy += extent.y_advance;
}
}
gfx->IdentityMatrix();
return gfx->PointInFill(gfxPoint(x, y));
cairo_identity_matrix(ctx);
return cairo_in_fill(ctx, x, y);
}
nsresult
@ -1342,38 +1410,15 @@ nsSVGGlyphFrame::GetGlobalTransform(gfxContext *aContext)
return NS_OK;
}
gfxTextRun *
nsSVGGlyphFrame::GetTextRun(gfxContext *aCtx, const nsString &aText)
{
// XXX: should really pass in GetPresContext()->AppUnitsPerDevPixel()
// instead of "1" and do the appropriate unit conversions when sending
// coordinates into thebes and pulling metrics out.
//
// References:
// https://bugzilla.mozilla.org/show_bug.cgi?id=375141
// http://weblogs.mozillazine.org/roc/archives/2007/03/text_text_text.html
gfxTextRunFactory::Parameters params =
{ aCtx, nsnull, nsnull,
nsnull, nsnull, nsnull,
1, // see note above
0 };
if (!mFontGroup)
return nsnull;
return mFontGroup->MakeTextRun(aText.get(), aText.Length(), &params);
}
//----------------------------------------------------------------------
// helper class
nsSVGGlyphFrame::nsSVGAutoGlyphHelperContext::nsSVGAutoGlyphHelperContext(
nsSVGGlyphFrame *aSource,
const nsString &aText,
const nsAString &aText,
nsSVGCharacterPosition **cp)
{
Init(aSource, aText);
Init(aSource);
nsresult rv = aSource->GetCharacterPosition(mCT, aText, cp);
if NS_FAILED(rv) {
@ -1381,10 +1426,8 @@ nsSVGGlyphFrame::nsSVGAutoGlyphHelperContext::nsSVGAutoGlyphHelperContext(
}
}
void
nsSVGGlyphFrame::nsSVGAutoGlyphHelperContext::Init(nsSVGGlyphFrame *aSource,
const nsString &aText)
void nsSVGGlyphFrame::nsSVGAutoGlyphHelperContext::Init(nsSVGGlyphFrame *aSource)
{
mCT = new gfxContext(nsSVGUtils::GetThebesComputationalSurface());
mTextRun = aSource->GetTextRun(mCT, aText);
aSource->SelectFont(mCT);
}

View File

@ -43,9 +43,7 @@
#include "nsISVGGlyphFragmentLeaf.h"
#include "nsISVGChildFrame.h"
#include "gfxContext.h"
#include "gfxFont.h"
struct nsSVGCharacterPosition;
class nsSVGTextFrame;
class nsSVGGlyphFrame;
@ -153,8 +151,8 @@ public:
protected:
struct nsSVGCharacterPosition {
gfxPoint pos;
gfxFloat angle;
float x, y;
PRBool draw;
};
@ -163,44 +161,45 @@ protected:
class nsSVGAutoGlyphHelperContext;
friend class nsSVGAutoGlyphHelperContext;
// A helper class to deal with gfxTextRuns and temporary thebes
// contexts. It destroys them when it goes out of scope.
// A helper class to deal with temporary cairo contexts.
// It destroys the context when it goes out of scope.
class nsSVGAutoGlyphHelperContext
{
public:
nsSVGAutoGlyphHelperContext(nsSVGGlyphFrame *aSource,
const nsString &aText)
nsSVGAutoGlyphHelperContext(nsSVGGlyphFrame *aSource)
{
Init(aSource, aText);
Init(aSource);
}
nsSVGAutoGlyphHelperContext(nsSVGGlyphFrame *aSource,
const nsString &aText,
const nsAString &aText,
nsSVGCharacterPosition **cp);
gfxContext *GetContext() { return mCT; }
gfxTextRun *GetTextRun() { return mTextRun; }
operator gfxContext * ()
{
return mCT;
}
operator cairo_t * ()
{
return mCT->GetCairo();
}
private:
void Init(nsSVGGlyphFrame *aSource, const nsString &aText);
void Init (nsSVGGlyphFrame *aSource);
nsRefPtr<gfxContext> mCT;
nsAutoPtr<gfxTextRun> mTextRun;
};
gfxTextRun *GetTextRun(gfxContext *aCtx,
const nsString &aText);
void SelectFont(gfxContext *aContext);
PRBool GetCharacterData(nsAString & aCharacterData);
nsresult GetCharacterPosition(gfxContext *aContext,
const nsString &aText,
const nsAString &aText,
nsSVGCharacterPosition **aCharacterPosition);
enum FillOrStroke { FILL, STROKE};
void LoopCharacters(gfxContext *aCtx, const nsString &aText,
const nsSVGCharacterPosition *aCP,
FillOrStroke aFillOrStroke);
static void LoopCharacters(cairo_t *aCtx,
const nsAString &aText,
const nsSVGCharacterPosition *aCP,
void (*aFunc)(cairo_t *cr, const char *utf8));
void UpdateGeometry(PRBool bRedraw, PRBool suppressInvalidation);
void UpdateMetrics();
@ -209,10 +208,8 @@ protected:
nsresult GetHighlight(PRUint32 *charnum, PRUint32 *nchars,
nscolor *foreground, nscolor *background);
nsRefPtr<gfxFontGroup> mFontGroup;
nsAutoPtr<gfxFontStyle> mFontStyle;
gfxPoint mPosition;
PRUint8 mWhitespaceHandling;
float mX, mY;
PRUint8 mWhitespaceHandling;
};
#endif