зеркало из https://github.com/mozilla/pjs.git
Bug 375141 - convert svg text to thebes. r=longsonr, sr=roc
This commit is contained in:
Родитель
2ae2f9b017
Коммит
784ad9d9d1
|
@ -53,7 +53,12 @@
|
||||||
#include "nsDOMError.h"
|
#include "nsDOMError.h"
|
||||||
#include "gfxContext.h"
|
#include "gfxContext.h"
|
||||||
#include "gfxMatrix.h"
|
#include "gfxMatrix.h"
|
||||||
#include "cairo.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.
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// Implementation
|
// Implementation
|
||||||
|
@ -117,6 +122,35 @@ nsSVGGlyphFrame::DidSetStyleContext()
|
||||||
{
|
{
|
||||||
nsSVGGlyphFrameBase::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();
|
return UpdateGraphic();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,23 +213,43 @@ nsSVGGlyphFrame::GetType() const
|
||||||
// nsISVGChildFrame methods
|
// nsISVGChildFrame methods
|
||||||
|
|
||||||
void
|
void
|
||||||
nsSVGGlyphFrame::LoopCharacters(cairo_t *aCtx, const nsAString &aText,
|
nsSVGGlyphFrame::LoopCharacters(gfxContext *aCtx, const nsString &aText,
|
||||||
const nsSVGCharacterPosition *aCP,
|
const nsSVGCharacterPosition *aCP,
|
||||||
void (*aFunc)(cairo_t *cr, const char *utf8))
|
FillOrStroke aFillOrStroke)
|
||||||
{
|
{
|
||||||
|
nsAutoPtr<gfxTextRun> textRun(GetTextRun(aCtx, aText));
|
||||||
|
|
||||||
|
if (!textRun)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!aCP) {
|
if (!aCP) {
|
||||||
aFunc(aCtx, NS_ConvertUTF16toUTF8(aText).get());
|
if (aFillOrStroke == STROKE) {
|
||||||
|
textRun->DrawToPath(aCtx, mPosition, 0, aText.Length(), nsnull, nsnull);
|
||||||
|
} else {
|
||||||
|
textRun->Draw(aCtx, mPosition, 0, aText.Length(),
|
||||||
|
nsnull, nsnull, nsnull);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
for (PRUint32 i = 0; i < aText.Length(); i++) {
|
for (PRUint32 i = 0; i < aText.Length(); i++) {
|
||||||
/* character actually on the path? */
|
/* character actually on the path? */
|
||||||
if (aCP[i].draw == PR_FALSE)
|
if (aCP[i].draw == PR_FALSE)
|
||||||
continue;
|
continue;
|
||||||
cairo_matrix_t matrix;
|
|
||||||
cairo_get_matrix(aCtx, &matrix);
|
gfxMatrix matrix = aCtx->CurrentMatrix();
|
||||||
cairo_move_to(aCtx, aCP[i].x, aCP[i].y);
|
|
||||||
cairo_rotate(aCtx, aCP[i].angle);
|
gfxMatrix rot;
|
||||||
aFunc(aCtx, NS_ConvertUTF16toUTF8(Substring(aText, i, 1)).get());
|
rot.Rotate(aCP[i].angle);
|
||||||
cairo_set_matrix(aCtx, &matrix);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,70 +268,62 @@ nsSVGGlyphFrame::PaintSVG(nsSVGRenderState *aContext, nsRect *aDirtyRect)
|
||||||
nsAutoArrayPtr<nsSVGCharacterPosition> cp;
|
nsAutoArrayPtr<nsSVGCharacterPosition> cp;
|
||||||
|
|
||||||
gfxContext *gfx = aContext->GetGfxContext();
|
gfxContext *gfx = aContext->GetGfxContext();
|
||||||
cairo_t *ctx = gfx->GetCairo();
|
|
||||||
|
|
||||||
SelectFont(gfx);
|
|
||||||
|
|
||||||
nsresult rv = GetCharacterPosition(gfx, text, getter_Transfers(cp));
|
nsresult rv = GetCharacterPosition(gfx, text, getter_Transfers(cp));
|
||||||
|
|
||||||
cairo_matrix_t matrix;
|
gfxMatrix matrix;
|
||||||
|
|
||||||
PRUint16 renderMode = aContext->GetRenderMode();
|
PRUint16 renderMode = aContext->GetRenderMode();
|
||||||
|
|
||||||
if (renderMode == nsSVGRenderState::NORMAL) {
|
if (renderMode == nsSVGRenderState::NORMAL) {
|
||||||
/* save/pop the state so we don't screw up the xform */
|
/* save/pop the state so we don't screw up the xform */
|
||||||
cairo_save(ctx);
|
gfx->Save();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cairo_get_matrix(ctx, &matrix);
|
matrix = gfx->CurrentMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = GetGlobalTransform(gfx);
|
rv = GetGlobalTransform(gfx);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
if (renderMode == nsSVGRenderState::NORMAL)
|
if (renderMode == nsSVGRenderState::NORMAL)
|
||||||
cairo_restore(ctx);
|
gfx->Restore();
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cp)
|
|
||||||
cairo_move_to(ctx, mX, mY);
|
|
||||||
|
|
||||||
if (renderMode != nsSVGRenderState::NORMAL) {
|
if (renderMode != nsSVGRenderState::NORMAL) {
|
||||||
if (GetClipRule() == NS_STYLE_FILL_RULE_EVENODD)
|
if (GetClipRule() == NS_STYLE_FILL_RULE_EVENODD)
|
||||||
cairo_set_fill_rule(ctx, CAIRO_FILL_RULE_EVEN_ODD);
|
gfx->SetFillRule(gfxContext::FILL_RULE_EVEN_ODD);
|
||||||
else
|
else
|
||||||
cairo_set_fill_rule(ctx, CAIRO_FILL_RULE_WINDING);
|
gfx->SetFillRule(gfxContext::FILL_RULE_WINDING);
|
||||||
|
|
||||||
if (renderMode == nsSVGRenderState::CLIP_MASK) {
|
if (renderMode == nsSVGRenderState::CLIP_MASK) {
|
||||||
cairo_set_antialias(ctx, CAIRO_ANTIALIAS_NONE);
|
gfx->SetAntialiasMode(gfxContext::MODE_ALIASED);
|
||||||
cairo_set_source_rgba(ctx, 1.0f, 1.0f, 1.0f, 1.0f);
|
gfx->SetColor(gfxRGBA(1.0f, 1.0f, 1.0f, 1.0f));
|
||||||
LoopCharacters(ctx, text, cp, cairo_show_text);
|
LoopCharacters(gfx, text, cp, FILL);
|
||||||
} else {
|
} else {
|
||||||
LoopCharacters(ctx, text, cp, cairo_text_path);
|
LoopCharacters(gfx, text, cp, STROKE);
|
||||||
}
|
}
|
||||||
|
|
||||||
cairo_set_matrix(ctx, &matrix);
|
gfx->SetMatrix(matrix);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *closure;
|
void *closure;
|
||||||
if (HasFill() && NS_SUCCEEDED(SetupCairoFill(gfx, &closure))) {
|
if (HasFill() && NS_SUCCEEDED(SetupCairoFill(gfx, &closure))) {
|
||||||
LoopCharacters(ctx, text, cp, cairo_show_text);
|
LoopCharacters(gfx, text, cp, FILL);
|
||||||
CleanupCairoFill(gfx, closure);
|
CleanupCairoFill(gfx, closure);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HasStroke() && NS_SUCCEEDED(SetupCairoStroke(gfx, &closure))) {
|
if (HasStroke() && NS_SUCCEEDED(SetupCairoStroke(gfx, &closure))) {
|
||||||
cairo_new_path(ctx);
|
gfx->NewPath();
|
||||||
if (!cp)
|
LoopCharacters(gfx, text, cp, STROKE);
|
||||||
cairo_move_to(ctx, mX, mY);
|
gfx->Stroke();
|
||||||
LoopCharacters(ctx, text, cp, cairo_text_path);
|
|
||||||
cairo_stroke(ctx);
|
|
||||||
CleanupCairoStroke(gfx, closure);
|
CleanupCairoStroke(gfx, closure);
|
||||||
cairo_new_path(ctx);
|
gfx->NewPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
cairo_restore(ctx);
|
gfx->Restore();
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -362,60 +408,64 @@ nsSVGGlyphFrame::UpdateCoveredRegion()
|
||||||
|
|
||||||
nsSVGAutoGlyphHelperContext ctx(this, text, getter_Transfers(cp));
|
nsSVGAutoGlyphHelperContext ctx(this, text, getter_Transfers(cp));
|
||||||
|
|
||||||
nsresult rv = GetGlobalTransform(ctx);
|
gfxContext *gfx = ctx.GetContext();
|
||||||
|
gfxTextRun *textRun = ctx.GetTextRun();
|
||||||
|
if (!gfx || !textRun)
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
nsresult rv = GetGlobalTransform(gfx);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
if (!cp) {
|
if (!cp) {
|
||||||
cairo_move_to(ctx, mX, mY);
|
|
||||||
|
|
||||||
if (hasStroke) {
|
if (hasStroke) {
|
||||||
cairo_text_path(ctx, NS_ConvertUTF16toUTF8(text).get());
|
textRun->DrawToPath(gfx, mPosition, 0, text.Length(), nsnull, nsnull);
|
||||||
} else {
|
} else {
|
||||||
cairo_text_extents_t extent;
|
gfxTextRun::Metrics metrics =
|
||||||
cairo_text_extents(ctx,
|
textRun->MeasureText(0, text.Length(), PR_FALSE, nsnull);
|
||||||
NS_ConvertUTF16toUTF8(text).get(),
|
gfx->Rectangle(metrics.mBoundingBox + mPosition);
|
||||||
&extent);
|
|
||||||
cairo_rectangle(ctx, mX + extent.x_bearing, mY + extent.y_bearing,
|
|
||||||
extent.width, extent.height);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cairo_matrix_t matrix;
|
|
||||||
for (PRUint32 i=0; i<text.Length(); i++) {
|
for (PRUint32 i=0; i<text.Length(); i++) {
|
||||||
/* character actually on the path? */
|
/* character actually on the path? */
|
||||||
if (cp[i].draw == PR_FALSE)
|
if (cp[i].draw == PR_FALSE)
|
||||||
continue;
|
continue;
|
||||||
cairo_get_matrix(ctx, &matrix);
|
|
||||||
cairo_move_to(ctx, cp[i].x, cp[i].y);
|
gfxMatrix matrix = gfx->CurrentMatrix();
|
||||||
cairo_rotate(ctx, cp[i].angle);
|
|
||||||
if (hasStroke) {
|
if (hasStroke) {
|
||||||
cairo_text_path(ctx, NS_ConvertUTF16toUTF8(Substring(text, i, 1)).get());
|
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);
|
||||||
} else {
|
} else {
|
||||||
cairo_text_extents_t extent;
|
gfx->MoveTo(cp[i].pos);
|
||||||
cairo_text_extents(ctx,
|
gfx->Rotate(cp[i].angle);
|
||||||
NS_ConvertUTF16toUTF8(Substring(text, i, 1)).get(),
|
|
||||||
&extent);
|
gfxTextRun::Metrics metrics =
|
||||||
cairo_rel_move_to(ctx, extent.x_bearing, extent.y_bearing);
|
textRun->MeasureText(i, 1, PR_FALSE, nsnull);
|
||||||
cairo_rel_line_to(ctx, extent.width, 0);
|
|
||||||
cairo_rel_line_to(ctx, 0, extent.height);
|
gfx->Rectangle(metrics.mBoundingBox + gfx->CurrentPoint());
|
||||||
cairo_rel_line_to(ctx, -extent.width, 0);
|
|
||||||
cairo_close_path(ctx);
|
|
||||||
}
|
}
|
||||||
cairo_set_matrix(ctx, &matrix);
|
gfx->SetMatrix(matrix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double xmin, ymin, xmax, ymax;
|
gfxRect extent;
|
||||||
|
|
||||||
if (hasStroke) {
|
if (hasStroke) {
|
||||||
SetupCairoStrokeGeometry(ctx);
|
SetupCairoStrokeGeometry(gfx);
|
||||||
cairo_stroke_extents(ctx, &xmin, &ymin, &xmax, &ymax);
|
extent = gfx->GetUserStrokeExtent();
|
||||||
nsSVGUtils::UserToDeviceBBox(ctx, &xmin, &ymin, &xmax, &ymax);
|
extent = gfx->UserToDevice(extent);
|
||||||
} else {
|
} else {
|
||||||
cairo_identity_matrix(ctx);
|
gfx->IdentityMatrix();
|
||||||
cairo_fill_extents(ctx, &xmin, &ymin, &xmax, &ymax);
|
extent = gfx->GetUserFillExtent();
|
||||||
}
|
}
|
||||||
|
|
||||||
mRect = nsSVGUtils::ToBoundingPixelRect(xmin, ymin, xmax, ymax);
|
mRect = nsSVGUtils::ToBoundingPixelRect(extent);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -473,21 +523,18 @@ nsSVGGlyphFrame::GetBBox(nsIDOMSVGRect **_retval)
|
||||||
|
|
||||||
nsSVGAutoGlyphHelperContext ctx(this, text, getter_Transfers(cp));
|
nsSVGAutoGlyphHelperContext ctx(this, text, getter_Transfers(cp));
|
||||||
|
|
||||||
nsresult rv = GetGlobalTransform(ctx);
|
gfxContext *gfx = ctx.GetContext();
|
||||||
|
if (!gfx)
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
nsresult rv = GetGlobalTransform(gfx);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
if (!cp)
|
LoopCharacters(gfx, text, cp, STROKE);
|
||||||
cairo_move_to(ctx, mX, mY);
|
gfx->IdentityMatrix();
|
||||||
|
gfxRect rect = gfx->GetUserFillExtent();
|
||||||
|
|
||||||
LoopCharacters(ctx, text, cp, cairo_text_path);
|
return NS_NewSVGRect(_retval, rect);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
@ -540,11 +587,9 @@ nsSVGGlyphFrame::GetCharacterData(nsAString & aCharacterData)
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsSVGGlyphFrame::GetCharacterPosition(gfxContext *aContext,
|
nsSVGGlyphFrame::GetCharacterPosition(gfxContext *aContext,
|
||||||
const nsAString &aText,
|
const nsString &aText,
|
||||||
nsSVGCharacterPosition **aCharacterPosition)
|
nsSVGCharacterPosition **aCharacterPosition)
|
||||||
{
|
{
|
||||||
cairo_t *ctx = aContext->GetCairo();
|
|
||||||
|
|
||||||
*aCharacterPosition = nsnull;
|
*aCharacterPosition = nsnull;
|
||||||
|
|
||||||
NS_ASSERTION(!aText.IsEmpty(), "no text");
|
NS_ASSERTION(!aText.IsEmpty(), "no text");
|
||||||
|
@ -565,20 +610,18 @@ nsSVGGlyphFrame::GetCharacterPosition(gfxContext *aContext,
|
||||||
float length = data->GetLength();
|
float length = data->GetLength();
|
||||||
PRUint32 strLength = aText.Length();
|
PRUint32 strLength = aText.Length();
|
||||||
|
|
||||||
|
nsAutoPtr<gfxTextRun> textRun(GetTextRun(aContext, aText));
|
||||||
|
if (!textRun)
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
nsSVGCharacterPosition *cp = new nsSVGCharacterPosition[strLength];
|
nsSVGCharacterPosition *cp = new nsSVGCharacterPosition[strLength];
|
||||||
|
|
||||||
for (PRUint32 k = 0; k < strLength; k++)
|
for (PRUint32 k = 0; k < strLength; k++)
|
||||||
cp[k].draw = PR_FALSE;
|
cp[k].draw = PR_FALSE;
|
||||||
|
|
||||||
float x = mX;
|
float x = mPosition.x;
|
||||||
for (PRUint32 i = 0; i < strLength; i++) {
|
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? */
|
/* have we run off the end of the path? */
|
||||||
if (x + halfAdvance > length)
|
if (x + halfAdvance > length)
|
||||||
|
@ -591,10 +634,10 @@ nsSVGGlyphFrame::GetCharacterPosition(gfxContext *aContext,
|
||||||
// add y (normal)
|
// add y (normal)
|
||||||
// add rotation
|
// add rotation
|
||||||
// move point back along tangent
|
// move point back along tangent
|
||||||
gfxPoint pt = data->FindPoint(gfxPoint(x + halfAdvance, mY),
|
gfxPoint pt = data->FindPoint(gfxPoint(x + halfAdvance, mPosition.y),
|
||||||
&(cp[i].angle));
|
&(cp[i].angle));
|
||||||
cp[i].x = pt.x - cos(cp[i].angle) * halfAdvance;
|
cp[i].pos =
|
||||||
cp[i].y = pt.y - sin(cp[i].angle) * halfAdvance;
|
pt - gfxPoint(cos(cp[i].angle), sin(cp[i].angle)) * halfAdvance;
|
||||||
}
|
}
|
||||||
x += 2 * halfAdvance;
|
x += 2 * halfAdvance;
|
||||||
}
|
}
|
||||||
|
@ -751,8 +794,7 @@ nsSVGGlyphFrame::GetHighlight(PRUint32 *charnum, PRUint32 *nchars,
|
||||||
NS_IMETHODIMP_(void)
|
NS_IMETHODIMP_(void)
|
||||||
nsSVGGlyphFrame::SetGlyphPosition(float x, float y)
|
nsSVGGlyphFrame::SetGlyphPosition(float x, float y)
|
||||||
{
|
{
|
||||||
mX = x;
|
mPosition.MoveTo(x, y);
|
||||||
mY = y;
|
|
||||||
UpdateGeometry(PR_TRUE, PR_FALSE);
|
UpdateGeometry(PR_TRUE, PR_FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -768,35 +810,26 @@ nsSVGGlyphFrame::GetStartPositionOfChar(PRUint32 charnum, nsIDOMSVGPoint **_retv
|
||||||
|
|
||||||
nsSVGAutoGlyphHelperContext ctx(this, text, getter_Transfers(cp));
|
nsSVGAutoGlyphHelperContext ctx(this, text, getter_Transfers(cp));
|
||||||
|
|
||||||
float x, y;
|
gfxPoint pt;
|
||||||
|
|
||||||
if (cp) {
|
if (cp) {
|
||||||
if (cp[charnum].draw == PR_FALSE) {
|
if (cp[charnum].draw == PR_FALSE) {
|
||||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
x = cp[charnum].x;
|
pt = cp[charnum].pos;
|
||||||
y = cp[charnum].y;
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
x = mX;
|
pt = mPosition;
|
||||||
y = mY;
|
|
||||||
|
|
||||||
if (charnum > 0) {
|
if (charnum > 0) {
|
||||||
cairo_text_extents_t extent;
|
gfxTextRun *textRun = ctx.GetTextRun();
|
||||||
|
if (!textRun)
|
||||||
cairo_text_extents(ctx,
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
NS_ConvertUTF16toUTF8(Substring(text,
|
pt.x += textRun->GetAdvanceWidth(0, charnum, nsnull);
|
||||||
0,
|
|
||||||
charnum)).get(),
|
|
||||||
&extent);
|
|
||||||
|
|
||||||
x += extent.x_advance;
|
|
||||||
y += extent.y_advance;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_NewSVGPoint(_retval, x, y);
|
return NS_NewSVGPoint(_retval, pt.x, pt.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
|
@ -808,33 +841,29 @@ nsSVGGlyphFrame::GetEndPositionOfChar(PRUint32 charnum, nsIDOMSVGPoint **_retval
|
||||||
GetCharacterData(text);
|
GetCharacterData(text);
|
||||||
|
|
||||||
nsAutoArrayPtr<nsSVGCharacterPosition> cp;
|
nsAutoArrayPtr<nsSVGCharacterPosition> cp;
|
||||||
|
|
||||||
nsSVGAutoGlyphHelperContext ctx(this, text, getter_Transfers(cp));
|
|
||||||
|
|
||||||
cairo_text_extents_t extent;
|
nsSVGAutoGlyphHelperContext ctx(this, text, getter_Transfers(cp));
|
||||||
|
gfxTextRun *textRun = ctx.GetTextRun();
|
||||||
|
if (!textRun)
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
if (cp) {
|
if (cp) {
|
||||||
if (cp[charnum].draw == PR_FALSE) {
|
if (cp[charnum].draw == PR_FALSE) {
|
||||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
cairo_text_extents(ctx,
|
float advance = textRun->GetAdvanceWidth(charnum, 1, nsnull);
|
||||||
NS_ConvertUTF16toUTF8(Substring(text, charnum, 1)).get(),
|
|
||||||
&extent);
|
|
||||||
|
|
||||||
float s = sin(cp[charnum].angle);
|
return NS_NewSVGPoint(_retval,
|
||||||
float c = cos(cp[charnum].angle);
|
cp[charnum].pos.x + advance * cos(cp[charnum].angle),
|
||||||
|
cp[charnum].pos.y + advance * sin(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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cairo_text_extents(ctx,
|
return NS_NewSVGPoint(_retval,
|
||||||
NS_ConvertUTF16toUTF8(Substring(text, 0, charnum + 1)).get(),
|
mPosition.x + textRun->GetAdvanceWidth(0,
|
||||||
&extent);
|
charnum + 1,
|
||||||
|
nsnull),
|
||||||
return NS_NewSVGPoint(_retval, mX + extent.x_advance, mY + extent.y_advance);
|
mPosition.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
|
@ -848,60 +877,47 @@ nsSVGGlyphFrame::GetExtentOfChar(PRUint32 charnum, nsIDOMSVGRect **_retval)
|
||||||
nsAutoArrayPtr<nsSVGCharacterPosition> cp;
|
nsAutoArrayPtr<nsSVGCharacterPosition> cp;
|
||||||
|
|
||||||
nsSVGAutoGlyphHelperContext ctx(this, text, getter_Transfers(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;
|
gfxTextRun::Metrics metrics =
|
||||||
cairo_text_extents(ctx,
|
textRun->MeasureText(charnum, 1, PR_FALSE, nsnull);
|
||||||
NS_ConvertUTF16toUTF8(Substring(text, charnum, 1)).get(),
|
|
||||||
&extent);
|
|
||||||
|
|
||||||
if (cp) {
|
if (cp) {
|
||||||
if (cp[charnum].draw == PR_FALSE) {
|
if (cp[charnum].draw == PR_FALSE) {
|
||||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
cairo_matrix_t matrix;
|
gfxContext *gfx = ctx.GetContext();
|
||||||
cairo_get_matrix(ctx, &matrix);
|
if (!gfx)
|
||||||
cairo_move_to(ctx, cp[charnum].x, cp[charnum].y);
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
cairo_rotate(ctx, cp[charnum].angle);
|
|
||||||
|
|
||||||
cairo_rel_move_to(ctx, extent.x_bearing, extent.y_bearing);
|
gfxMatrix matrix = gfx->CurrentMatrix();
|
||||||
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);
|
|
||||||
|
|
||||||
double xmin, ymin, xmax, ymax;
|
gfx->MoveTo(cp[charnum].pos);
|
||||||
|
gfx->Rotate(cp[charnum].angle);
|
||||||
|
|
||||||
cairo_fill_extents(ctx, &xmin, &ymin, &xmax, &ymax);
|
gfx->Rectangle(metrics.mBoundingBox + gfx->CurrentPoint());
|
||||||
|
|
||||||
cairo_set_matrix(ctx, &matrix);
|
gfx->IdentityMatrix();
|
||||||
|
|
||||||
return NS_NewSVGRect(_retval, xmin, ymin, xmax - xmin, ymax - ymin);
|
gfxRect rect = gfx->GetUserFillExtent();
|
||||||
|
|
||||||
|
gfx->SetMatrix(matrix);
|
||||||
|
|
||||||
|
return NS_NewSVGRect(_retval, rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
float x = mX;
|
gfxPoint pt = mPosition;
|
||||||
float y = mY;
|
|
||||||
|
|
||||||
x += extent.x_bearing;
|
|
||||||
y += extent.y_bearing;
|
|
||||||
|
|
||||||
cairo_text_extents_t precedingExtent;
|
|
||||||
|
|
||||||
if (charnum > 0) {
|
if (charnum > 0) {
|
||||||
// add the space taken up by the text which comes before charnum
|
// add the space taken up by the text which comes before charnum
|
||||||
// to the position of the charnum character
|
// to the position of the charnum character
|
||||||
cairo_text_extents(ctx,
|
pt.x += textRun->GetAdvanceWidth(0, charnum, nsnull);
|
||||||
NS_ConvertUTF16toUTF8(Substring(text,
|
|
||||||
0,
|
|
||||||
charnum)).get(),
|
|
||||||
&precedingExtent);
|
|
||||||
|
|
||||||
x += precedingExtent.x_advance;
|
|
||||||
y += precedingExtent.y_advance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_NewSVGRect(_retval, x, y, extent.width, extent.height);
|
return NS_NewSVGRect(_retval, metrics.mBoundingBox + pt);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
|
@ -932,32 +948,38 @@ NS_IMETHODIMP_(float)
|
||||||
nsSVGGlyphFrame::GetBaselineOffset(PRUint16 baselineIdentifier)
|
nsSVGGlyphFrame::GetBaselineOffset(PRUint16 baselineIdentifier)
|
||||||
{
|
{
|
||||||
float _retval;
|
float _retval;
|
||||||
cairo_font_extents_t extents;
|
|
||||||
|
|
||||||
nsSVGAutoGlyphHelperContext ctx(this);
|
nsAutoString text;
|
||||||
|
GetCharacterData(text);
|
||||||
|
|
||||||
cairo_font_extents(ctx, &extents);
|
nsSVGAutoGlyphHelperContext ctx(this, text);
|
||||||
|
gfxTextRun *textRun = ctx.GetTextRun();
|
||||||
|
if (!textRun)
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
gfxTextRun::Metrics metrics =
|
||||||
|
textRun->MeasureText(0, text.Length(), PR_FALSE, nsnull);
|
||||||
|
|
||||||
switch (baselineIdentifier) {
|
switch (baselineIdentifier) {
|
||||||
case BASELINE_HANGING:
|
case BASELINE_HANGING:
|
||||||
// not really right, but the best we can do with the information provided
|
// not really right, but the best we can do with the information provided
|
||||||
// FALLTHROUGH
|
// FALLTHROUGH
|
||||||
case BASELINE_TEXT_BEFORE_EDGE:
|
case BASELINE_TEXT_BEFORE_EDGE:
|
||||||
_retval = -extents.ascent;
|
_retval = -metrics.mAscent;
|
||||||
break;
|
break;
|
||||||
case BASELINE_TEXT_AFTER_EDGE:
|
case BASELINE_TEXT_AFTER_EDGE:
|
||||||
_retval = extents.descent;
|
_retval = metrics.mDescent;
|
||||||
break;
|
break;
|
||||||
case BASELINE_CENTRAL:
|
case BASELINE_CENTRAL:
|
||||||
case BASELINE_MIDDLE:
|
case BASELINE_MIDDLE:
|
||||||
_retval = - (extents.ascent - extents.descent) / 2.0;
|
_retval = - (metrics.mAscent - metrics.mDescent) / 2.0;
|
||||||
break;
|
break;
|
||||||
case BASELINE_ALPHABETIC:
|
case BASELINE_ALPHABETIC:
|
||||||
default:
|
default:
|
||||||
_retval = 0.0;
|
_retval = 0.0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _retval;
|
return _retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -969,14 +991,12 @@ nsSVGGlyphFrame::GetAdvance()
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsSVGAutoGlyphHelperContext ctx(this);
|
nsSVGAutoGlyphHelperContext ctx(this, text);
|
||||||
|
gfxTextRun *textRun = ctx.GetTextRun();
|
||||||
|
if (!textRun)
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
cairo_text_extents_t extents;
|
return textRun->GetAdvanceWidth(0, text.Length(), nsnull);
|
||||||
cairo_text_extents(ctx,
|
|
||||||
NS_ConvertUTF16toUTF8(text).get(),
|
|
||||||
&extents);
|
|
||||||
|
|
||||||
return extents.x_advance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP_(nsSVGTextPathFrame*)
|
NS_IMETHODIMP_(nsSVGTextPathFrame*)
|
||||||
|
@ -1104,19 +1124,7 @@ nsSVGGlyphFrame::GetNumberOfChars()
|
||||||
NS_IMETHODIMP_(float)
|
NS_IMETHODIMP_(float)
|
||||||
nsSVGGlyphFrame::GetComputedTextLength()
|
nsSVGGlyphFrame::GetComputedTextLength()
|
||||||
{
|
{
|
||||||
nsAutoString text;
|
return GetAdvance();
|
||||||
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)
|
NS_IMETHODIMP_(float)
|
||||||
|
@ -1125,14 +1133,12 @@ nsSVGGlyphFrame::GetSubStringLength(PRUint32 charnum, PRUint32 fragmentChars)
|
||||||
nsAutoString text;
|
nsAutoString text;
|
||||||
GetCharacterData(text);
|
GetCharacterData(text);
|
||||||
|
|
||||||
nsSVGAutoGlyphHelperContext ctx(this);
|
nsSVGAutoGlyphHelperContext ctx(this, text);
|
||||||
|
gfxTextRun *textRun = ctx.GetTextRun();
|
||||||
|
if (!textRun)
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
cairo_text_extents_t extent;
|
return textRun->GetAdvanceWidth(charnum, fragmentChars, nsnull);
|
||||||
cairo_text_extents(ctx,
|
|
||||||
NS_ConvertUTF16toUTF8(Substring(text, charnum, fragmentChars)).get(),
|
|
||||||
&extent);
|
|
||||||
|
|
||||||
return fabs(extent.x_advance) + fabs(extent.y_advance);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP_(PRInt32)
|
NS_IMETHODIMP_(PRInt32)
|
||||||
|
@ -1149,55 +1155,48 @@ nsSVGGlyphFrame::GetCharNumAtPosition(nsIDOMSVGPoint *point)
|
||||||
|
|
||||||
nsSVGAutoGlyphHelperContext ctx(this, text, getter_Transfers(cp));
|
nsSVGAutoGlyphHelperContext ctx(this, text, getter_Transfers(cp));
|
||||||
|
|
||||||
float x, y;
|
gfxPoint pt;
|
||||||
if (!cp) {
|
if (!cp) {
|
||||||
x = mX;
|
pt = mPosition;
|
||||||
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++) {
|
for (PRUint32 charnum = 0; charnum < text.Length(); charnum++) {
|
||||||
/* character actually on the path? */
|
/* character actually on the path? */
|
||||||
if (cp && cp[charnum].draw == PR_FALSE)
|
if (cp && cp[charnum].draw == PR_FALSE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
cairo_matrix_t matrix;
|
gfxMatrix matrix = gfx->CurrentMatrix();
|
||||||
cairo_get_matrix(ctx, &matrix);
|
gfx->NewPath();
|
||||||
cairo_new_path(ctx);
|
|
||||||
|
|
||||||
if (cp) {
|
if (cp) {
|
||||||
cairo_move_to(ctx, cp[charnum].x, cp[charnum].y);
|
gfx->MoveTo(cp[charnum].pos);
|
||||||
cairo_rotate(ctx, cp[charnum].angle);
|
gfx->Rotate(cp[charnum].angle);
|
||||||
} else {
|
} else {
|
||||||
if (charnum > 0) {
|
if (charnum > 0) {
|
||||||
cairo_text_extents_t extent;
|
gfx->MoveTo(pt + gfxPoint(textRun->GetAdvanceWidth(0, charnum, nsnull),
|
||||||
|
0));
|
||||||
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 {
|
} else {
|
||||||
cairo_move_to(ctx, x, y);
|
gfx->MoveTo(pt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cairo_text_extents_t extent;
|
|
||||||
cairo_text_extents(ctx,
|
|
||||||
NS_ConvertUTF16toUTF8(Substring(text, charnum, 1)).get(),
|
|
||||||
&extent);
|
|
||||||
|
|
||||||
cairo_rel_move_to(ctx, extent.x_bearing, extent.y_bearing);
|
gfxTextRun::Metrics metrics =
|
||||||
cairo_rel_line_to(ctx, extent.width, 0);
|
textRun->MeasureText(charnum, 1, PR_FALSE, nsnull);
|
||||||
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->Rectangle(metrics.mBoundingBox + gfx->CurrentPoint());
|
||||||
if (cairo_in_fill(ctx, xPos, yPos)) {
|
|
||||||
|
gfx->IdentityMatrix();
|
||||||
|
if (gfx->PointInFill(gfxPoint(xPos, yPos))) {
|
||||||
|
gfx->SetMatrix(matrix);
|
||||||
return charnum;
|
return charnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
cairo_set_matrix(ctx, &matrix);
|
gfx->SetMatrix(matrix);
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1237,68 +1236,6 @@ 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,
|
void nsSVGGlyphFrame::UpdateGeometry(PRBool bRedraw,
|
||||||
PRBool suppressInvalidation)
|
PRBool suppressInvalidation)
|
||||||
{
|
{
|
||||||
|
@ -1343,52 +1280,47 @@ nsSVGGlyphFrame::ContainsPoint(float x, float y)
|
||||||
nsAutoArrayPtr<nsSVGCharacterPosition> cp;
|
nsAutoArrayPtr<nsSVGCharacterPosition> cp;
|
||||||
|
|
||||||
nsSVGAutoGlyphHelperContext ctx(this, text, getter_Transfers(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(ctx);
|
nsresult rv = GetGlobalTransform(gfx);
|
||||||
NS_ENSURE_SUCCESS(rv, PR_FALSE);
|
NS_ENSURE_SUCCESS(rv, PR_FALSE);
|
||||||
|
|
||||||
float xx = 0, yy = 0;
|
gfxPoint pt;
|
||||||
if (!cp) {
|
if (!cp) {
|
||||||
xx = mX;
|
pt = mPosition;
|
||||||
yy = mY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cairo_matrix_t matrix;
|
|
||||||
|
|
||||||
for (PRUint32 i = 0; i < text.Length(); i++) {
|
for (PRUint32 i = 0; i < text.Length(); i++) {
|
||||||
/* character actually on the path? */
|
/* character actually on the path? */
|
||||||
if (cp && cp[i].draw == PR_FALSE)
|
if (cp && cp[i].draw == PR_FALSE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
cairo_get_matrix(ctx, &matrix);
|
gfxMatrix matrix = gfx->CurrentMatrix();
|
||||||
|
|
||||||
if (cp) {
|
if (cp) {
|
||||||
cairo_move_to(ctx, cp[i].x, cp[i].y);
|
gfx->MoveTo(cp[i].pos);
|
||||||
cairo_rotate(ctx, cp[i].angle);
|
gfx->Rotate(cp[i].angle);
|
||||||
} else {
|
} else {
|
||||||
cairo_move_to(ctx, xx, yy);
|
gfx->MoveTo(pt);
|
||||||
}
|
}
|
||||||
|
|
||||||
cairo_text_extents_t extent;
|
gfxTextRun::Metrics metrics =
|
||||||
cairo_text_extents(ctx,
|
textRun->MeasureText(i, 1, PR_FALSE, nsnull);
|
||||||
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);
|
|
||||||
|
|
||||||
cairo_set_matrix(ctx, &matrix);
|
gfx->Rectangle(metrics.mBoundingBox + gfx->CurrentPoint());
|
||||||
|
|
||||||
|
gfx->SetMatrix(matrix);
|
||||||
|
|
||||||
if (!cp) {
|
if (!cp) {
|
||||||
xx += extent.x_advance;
|
pt.x += metrics.mAdvanceWidth;
|
||||||
yy += extent.y_advance;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cairo_identity_matrix(ctx);
|
gfx->IdentityMatrix();
|
||||||
return cairo_in_fill(ctx, x, y);
|
return gfx->PointInFill(gfxPoint(x, y));
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
|
@ -1410,15 +1342,38 @@ nsSVGGlyphFrame::GetGlobalTransform(gfxContext *aContext)
|
||||||
return NS_OK;
|
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(), ¶ms);
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// helper class
|
// helper class
|
||||||
|
|
||||||
nsSVGGlyphFrame::nsSVGAutoGlyphHelperContext::nsSVGAutoGlyphHelperContext(
|
nsSVGGlyphFrame::nsSVGAutoGlyphHelperContext::nsSVGAutoGlyphHelperContext(
|
||||||
nsSVGGlyphFrame *aSource,
|
nsSVGGlyphFrame *aSource,
|
||||||
const nsAString &aText,
|
const nsString &aText,
|
||||||
nsSVGCharacterPosition **cp)
|
nsSVGCharacterPosition **cp)
|
||||||
{
|
{
|
||||||
Init(aSource);
|
Init(aSource, aText);
|
||||||
|
|
||||||
nsresult rv = aSource->GetCharacterPosition(mCT, aText, cp);
|
nsresult rv = aSource->GetCharacterPosition(mCT, aText, cp);
|
||||||
if NS_FAILED(rv) {
|
if NS_FAILED(rv) {
|
||||||
|
@ -1426,8 +1381,10 @@ nsSVGGlyphFrame::nsSVGAutoGlyphHelperContext::nsSVGAutoGlyphHelperContext(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsSVGGlyphFrame::nsSVGAutoGlyphHelperContext::Init(nsSVGGlyphFrame *aSource)
|
void
|
||||||
|
nsSVGGlyphFrame::nsSVGAutoGlyphHelperContext::Init(nsSVGGlyphFrame *aSource,
|
||||||
|
const nsString &aText)
|
||||||
{
|
{
|
||||||
mCT = new gfxContext(nsSVGUtils::GetThebesComputationalSurface());
|
mCT = new gfxContext(nsSVGUtils::GetThebesComputationalSurface());
|
||||||
aSource->SelectFont(mCT);
|
mTextRun = aSource->GetTextRun(mCT, aText);
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,9 @@
|
||||||
#include "nsISVGGlyphFragmentLeaf.h"
|
#include "nsISVGGlyphFragmentLeaf.h"
|
||||||
#include "nsISVGChildFrame.h"
|
#include "nsISVGChildFrame.h"
|
||||||
#include "gfxContext.h"
|
#include "gfxContext.h"
|
||||||
|
#include "gfxFont.h"
|
||||||
|
|
||||||
|
struct nsSVGCharacterPosition;
|
||||||
class nsSVGTextFrame;
|
class nsSVGTextFrame;
|
||||||
class nsSVGGlyphFrame;
|
class nsSVGGlyphFrame;
|
||||||
|
|
||||||
|
@ -151,8 +153,8 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct nsSVGCharacterPosition {
|
struct nsSVGCharacterPosition {
|
||||||
|
gfxPoint pos;
|
||||||
gfxFloat angle;
|
gfxFloat angle;
|
||||||
float x, y;
|
|
||||||
PRBool draw;
|
PRBool draw;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -161,45 +163,44 @@ protected:
|
||||||
class nsSVGAutoGlyphHelperContext;
|
class nsSVGAutoGlyphHelperContext;
|
||||||
friend class nsSVGAutoGlyphHelperContext;
|
friend class nsSVGAutoGlyphHelperContext;
|
||||||
|
|
||||||
// A helper class to deal with temporary cairo contexts.
|
// A helper class to deal with gfxTextRuns and temporary thebes
|
||||||
// It destroys the context when it goes out of scope.
|
// contexts. It destroys them when it goes out of scope.
|
||||||
class nsSVGAutoGlyphHelperContext
|
class nsSVGAutoGlyphHelperContext
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
nsSVGAutoGlyphHelperContext(nsSVGGlyphFrame *aSource)
|
nsSVGAutoGlyphHelperContext(nsSVGGlyphFrame *aSource,
|
||||||
|
const nsString &aText)
|
||||||
{
|
{
|
||||||
Init(aSource);
|
Init(aSource, aText);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsSVGAutoGlyphHelperContext(nsSVGGlyphFrame *aSource,
|
nsSVGAutoGlyphHelperContext(nsSVGGlyphFrame *aSource,
|
||||||
const nsAString &aText,
|
const nsString &aText,
|
||||||
nsSVGCharacterPosition **cp);
|
nsSVGCharacterPosition **cp);
|
||||||
|
|
||||||
operator gfxContext * ()
|
gfxContext *GetContext() { return mCT; }
|
||||||
{
|
gfxTextRun *GetTextRun() { return mTextRun; }
|
||||||
return mCT;
|
|
||||||
}
|
|
||||||
|
|
||||||
operator cairo_t * ()
|
|
||||||
{
|
|
||||||
return mCT->GetCairo();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Init (nsSVGGlyphFrame *aSource);
|
void Init(nsSVGGlyphFrame *aSource, const nsString &aText);
|
||||||
|
|
||||||
nsRefPtr<gfxContext> mCT;
|
nsRefPtr<gfxContext> mCT;
|
||||||
|
nsAutoPtr<gfxTextRun> mTextRun;
|
||||||
};
|
};
|
||||||
|
|
||||||
void SelectFont(gfxContext *aContext);
|
gfxTextRun *GetTextRun(gfxContext *aCtx,
|
||||||
|
const nsString &aText);
|
||||||
|
|
||||||
PRBool GetCharacterData(nsAString & aCharacterData);
|
PRBool GetCharacterData(nsAString & aCharacterData);
|
||||||
nsresult GetCharacterPosition(gfxContext *aContext,
|
nsresult GetCharacterPosition(gfxContext *aContext,
|
||||||
const nsAString &aText,
|
const nsString &aText,
|
||||||
nsSVGCharacterPosition **aCharacterPosition);
|
nsSVGCharacterPosition **aCharacterPosition);
|
||||||
static void LoopCharacters(cairo_t *aCtx,
|
|
||||||
const nsAString &aText,
|
enum FillOrStroke { FILL, STROKE};
|
||||||
const nsSVGCharacterPosition *aCP,
|
|
||||||
void (*aFunc)(cairo_t *cr, const char *utf8));
|
void LoopCharacters(gfxContext *aCtx, const nsString &aText,
|
||||||
|
const nsSVGCharacterPosition *aCP,
|
||||||
|
FillOrStroke aFillOrStroke);
|
||||||
|
|
||||||
void UpdateGeometry(PRBool bRedraw, PRBool suppressInvalidation);
|
void UpdateGeometry(PRBool bRedraw, PRBool suppressInvalidation);
|
||||||
void UpdateMetrics();
|
void UpdateMetrics();
|
||||||
|
@ -208,8 +209,10 @@ protected:
|
||||||
nsresult GetHighlight(PRUint32 *charnum, PRUint32 *nchars,
|
nsresult GetHighlight(PRUint32 *charnum, PRUint32 *nchars,
|
||||||
nscolor *foreground, nscolor *background);
|
nscolor *foreground, nscolor *background);
|
||||||
|
|
||||||
float mX, mY;
|
nsRefPtr<gfxFontGroup> mFontGroup;
|
||||||
PRUint8 mWhitespaceHandling;
|
nsAutoPtr<gfxFontStyle> mFontStyle;
|
||||||
|
gfxPoint mPosition;
|
||||||
|
PRUint8 mWhitespaceHandling;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Загрузка…
Ссылка в новой задаче