mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-12 10:40:12 +00:00
Bug 392233. Take the current contxt scale into account when constructing textruns for SVG, and simplify the SVG text code. r=longsonr,sr=vlad
This commit is contained in:
parent
b903fbc5b9
commit
f3f684e136
@ -47,6 +47,8 @@ include $(topsrcdir)/config/rules.mk
|
||||
_TEST_FILES = \
|
||||
test_getSubStringLength.xhtml \
|
||||
getSubStringLength-helper.svg \
|
||||
test_text.html \
|
||||
text-helper.svg \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_TEST_FILES)
|
||||
|
180
content/svg/content/test/test_text.html
Normal file
180
content/svg/content/test/test_text.html
Normal file
@ -0,0 +1,180 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=392233
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 392233</title>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=392233">Mozilla Bug 392233</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
|
||||
<iframe id="svg" src="text-helper.svg"></iframe>
|
||||
|
||||
<pre id="test">
|
||||
<script class="testbody" type="application/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function runTest()
|
||||
{
|
||||
var doc = $("svg").contentWindow.document;
|
||||
var text1 = doc.getElementById("text1");
|
||||
var text2 = doc.getElementById("text2");
|
||||
var text3 = doc.getElementById("text3");
|
||||
|
||||
var charWidth = text1.getSubStringLength(0, 1);
|
||||
|
||||
function isPoint(pt1, x, y, str)
|
||||
{
|
||||
is(pt1.x, x, str + " x");
|
||||
is(pt1.y, y, str + " y");
|
||||
}
|
||||
|
||||
function ymost(r)
|
||||
{
|
||||
return r.y + r.height;
|
||||
}
|
||||
|
||||
function xmost(r)
|
||||
{
|
||||
return r.x + r.width;
|
||||
}
|
||||
|
||||
var p = text1.getStartPositionOfChar(0);
|
||||
|
||||
// Simple horizontal string
|
||||
|
||||
is(text1.getNumberOfChars(), 3, "text1 length");
|
||||
ok(text1.getComputedTextLength() > 0, "text1 measured length");
|
||||
is(text1.getComputedTextLength(), text1.getSubStringLength(0, 3), "text1 substring length");
|
||||
isPoint(text1.getStartPositionOfChar(0), 5, 25, "text1 char 0 start offset");
|
||||
isPoint(text1.getStartPositionOfChar(1), 5 + charWidth, 25, "text1 char 1 start offset");
|
||||
isPoint(text1.getStartPositionOfChar(2), 5 + 2*charWidth, 25, "text1 char 2 start offset");
|
||||
isPoint(text1.getEndPositionOfChar(0), 5 + charWidth, 25, "text1 char 0 end offset");
|
||||
isPoint(text1.getEndPositionOfChar(1), 5 + 2*charWidth, 25, "text1 char 1 end offset");
|
||||
isPoint(text1.getEndPositionOfChar(2), 5 + 3*charWidth, 25, "text1 char 2 end offset");
|
||||
is(text1.getExtentOfChar(0).x, 5, "text1 char 0 extent x");
|
||||
is(text1.getExtentOfChar(0).width, text1.getSubStringLength(0, 1), "text1 char 0 extent width");
|
||||
ok(text1.getExtentOfChar(0).y < 25, "text1 char 0 extent y");
|
||||
ok(ymost(text1.getExtentOfChar(0)) > 25, "text1 char 0 extent height");
|
||||
is(text1.getExtentOfChar(1).x, 5 + charWidth, "text1 char 1 extent x");
|
||||
is(text1.getExtentOfChar(1).width, text1.getSubStringLength(0, 1), "text1 char 1 extent width");
|
||||
is(text1.getExtentOfChar(1).y, text1.getExtentOfChar(0).y, "text1 char 0/1 extent y");
|
||||
is(text1.getExtentOfChar(1).height, text1.getExtentOfChar(0).height, "text1 char 0/1 extent height");
|
||||
is(text1.getExtentOfChar(2).x, 5 + 2*charWidth, "text1 char 2 extent x");
|
||||
is(text1.getExtentOfChar(2).width, text1.getSubStringLength(0, 1), "text1 char 2 extent width");
|
||||
is(text1.getExtentOfChar(2).y, text1.getExtentOfChar(0).y, "text1 char 0/2 extent y");
|
||||
is(text1.getExtentOfChar(2).height, text1.getExtentOfChar(0).height, "text1 char 0/2 extent height");
|
||||
is(text1.getRotationOfChar(0), 0, "text1 char 0 rotation");
|
||||
is(text1.getRotationOfChar(1), 0, "text1 char 0 rotation");
|
||||
is(text1.getRotationOfChar(2), 0, "text1 char 0 rotation");
|
||||
p.x = 5 + 0.1;
|
||||
p.y = 25;
|
||||
is(text1.getCharNumAtPosition(p), 0, "text1 finding char 0 left edge");
|
||||
p.x = 5 + charWidth - 0.1;
|
||||
is(text1.getCharNumAtPosition(p), 0, "text1 finding char 0 on right");
|
||||
p.x = 5 - 0.1;
|
||||
is(text1.getCharNumAtPosition(p), -1, "text1 finding no char on left");
|
||||
p.x = 5 + 0.1;
|
||||
p.y = text1.getExtentOfChar(0).y - 0.1;
|
||||
is(text1.getCharNumAtPosition(p), -1, "text1 finding no char on top");
|
||||
p.y = text1.getExtentOfChar(0).y + 0.1;
|
||||
is(text1.getCharNumAtPosition(p), 0, "text1 finding char 0 top edge");
|
||||
p.x = 5 + 3*charWidth - 0.1;
|
||||
is(text1.getCharNumAtPosition(p), 2, "text1 finding char 2 top edge");
|
||||
p.x = 5 + 3*charWidth + 0.1;
|
||||
is(text1.getCharNumAtPosition(p), -1, "text1 finding no char on right");
|
||||
|
||||
// Simple rotated-90 string ... width might change because of hinting
|
||||
|
||||
charWidth = text2.getSubStringLength(0, 1);
|
||||
|
||||
is(text2.getNumberOfChars(), 3, "text2 length");
|
||||
ok(text2.getComputedTextLength() > 0, "text2 measured length");
|
||||
is(text2.getComputedTextLength(), text2.getSubStringLength(0, 3), "text2 substring length");
|
||||
isPoint(text2.getStartPositionOfChar(0), 100, 125, "text2 char 0 start offset");
|
||||
isPoint(text2.getStartPositionOfChar(1), 100, 125 + charWidth, "text2 char 1 start offset");
|
||||
isPoint(text2.getStartPositionOfChar(2), 100, 125 + 2*charWidth, "text2 char 2 start offset");
|
||||
isPoint(text2.getEndPositionOfChar(0), 100, 125 + charWidth, "text2 char 0 end offset");
|
||||
isPoint(text2.getEndPositionOfChar(1), 100, 125 + 2*charWidth, "text2 char 1 end offset");
|
||||
isPoint(text2.getEndPositionOfChar(2), 100, 125 + 3*charWidth, "text2 char 2 end offset");
|
||||
is(text2.getExtentOfChar(0).y, 125, "text2 char 0 extent y");
|
||||
is(text2.getExtentOfChar(0).height, charWidth, "text2 char 0 extent height");
|
||||
ok(text2.getExtentOfChar(0).width < 100, "text2 char 0 extent x");
|
||||
ok(xmost(text2.getExtentOfChar(0)) > 100, "text2 char 0 extent width");
|
||||
is(text2.getExtentOfChar(1).y, 125 + charWidth, "text2 char 1 extent x");
|
||||
is(text2.getExtentOfChar(1).height, text2.getSubStringLength(0, 1), "text2 char 1 extent width");
|
||||
is(text2.getExtentOfChar(1).x, text2.getExtentOfChar(0).x, "text2 char 0/1 extent y");
|
||||
is(text2.getExtentOfChar(1).width, text2.getExtentOfChar(0).width, "text2 char 0/1 extent height");
|
||||
is(text2.getExtentOfChar(2).y, 125 + 2*charWidth, "text2 char 2 extent x");
|
||||
is(text2.getExtentOfChar(2).height, text2.getSubStringLength(0, 1), "text2 char 2 extent width");
|
||||
is(text2.getExtentOfChar(2).x, text2.getExtentOfChar(0).x, "text2 char 0/2 extent y");
|
||||
is(text2.getExtentOfChar(2).width, text2.getExtentOfChar(0).width, "text2 char 0/2 extent height");
|
||||
is(text2.getRotationOfChar(0), 90, "text2 char 0 rotation");
|
||||
is(text2.getRotationOfChar(1), 90, "text2 char 0 rotation");
|
||||
is(text2.getRotationOfChar(2), 90, "text2 char 0 rotation");
|
||||
p.y = 125 + 0.1;
|
||||
p.x = 100;
|
||||
is(text2.getCharNumAtPosition(p), 0, "text2 finding char 0 top edge");
|
||||
p.y = 125 + charWidth - 0.1;
|
||||
is(text2.getCharNumAtPosition(p), 0, "text2 finding char 0 on bottom");
|
||||
p.y = 125 - 0.1;
|
||||
is(text2.getCharNumAtPosition(p), -1, "text2 finding no char on top");
|
||||
p.y = 125 + 0.1;
|
||||
p.x = text2.getExtentOfChar(0).x - 0.1;
|
||||
is(text2.getCharNumAtPosition(p), -1, "text2 finding no char on left");
|
||||
p.x = text2.getExtentOfChar(0).x + 0.1;
|
||||
is(text2.getCharNumAtPosition(p), 0, "text2 finding char 0 left edge");
|
||||
p.y = 125 + 3*charWidth - 0.1;
|
||||
is(text2.getCharNumAtPosition(p), 2, "text2 finding char 2 bottom edge");
|
||||
p.y = 1225 + 3*charWidth + 0.1;
|
||||
is(text2.getCharNumAtPosition(p), -1, "text2 finding no char on bottom");
|
||||
|
||||
// Text along a thin rectangle path
|
||||
|
||||
charWidth = text3.getSubStringLength(0, 1);
|
||||
|
||||
is(text3.getNumberOfChars(), 26, "text3 length");
|
||||
ok(text3.getComputedTextLength() > 0, "text3 measured length");
|
||||
is(text3.getComputedTextLength(), text3.getSubStringLength(0, 26), "text3 substring length");
|
||||
|
||||
// character 12 should be on the bottom side
|
||||
is(text3.getStartPositionOfChar(12).y, 253, "text3 char 12 start offset");
|
||||
is(text3.getEndPositionOfChar(12).y, 253, "text3 char 12 end offset");
|
||||
ok(text3.getExtentOfChar(12).y < 253, "text3 char 12 extent y");
|
||||
ok(ymost(text3.getExtentOfChar(12)) > 253, "text3 char 12 extent height");
|
||||
is(text3.getRotationOfChar(12), 180, "text3 char 12 rotation");
|
||||
p.x = text3.getExtentOfChar(12).x + 0.1;
|
||||
p.y = ymost(text3.getExtentOfChar(12)) - 0.1;
|
||||
is(text3.getCharNumAtPosition(p), 12, "text3 finding char 12");
|
||||
// This next test is tricky. The glyph for character 3 may overlap from the above
|
||||
// but character 12 wins because it's the last to render
|
||||
p.y = text3.getExtentOfChar(12).y + 0.1;
|
||||
is(text3.getCharNumAtPosition(p), 12, "text3 finding last rendered char");
|
||||
|
||||
// character 25 should be beyond the end of the path
|
||||
// Not sure what should happen here. Currently we throw, which seems wrong
|
||||
// is(text3.getStartPositionOfChar(25).x, 0, "text3 char 25 start offset");
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
runTest();
|
||||
|
||||
var doc = $("svg").contentWindow.document;
|
||||
doc.getElementById("g").setAttribute("transform", "rotate(90 200 200)");
|
||||
|
||||
runTest();
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
window.addEventListener("load", runTests, false);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
17
content/svg/content/test/text-helper.svg
Normal file
17
content/svg/content/test/text-helper.svg
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="750"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
|
||||
<style type="text/css">
|
||||
text { font: 20px monospace; }
|
||||
</style>
|
||||
|
||||
<g id="g">
|
||||
<text id="text1" x="5" y="25">abc</text>
|
||||
|
||||
<path id="MyPath2" d="M 100 125 L 100 200" stroke="red" fill="none"/>
|
||||
<text id="text2"><textPath xlink:href="#MyPath2">abc</textPath></text>
|
||||
|
||||
<path id="MyPath" d="M 5 250 L 105 250 L 105 253 L 5 253 z" stroke="red" fill="none"/>
|
||||
<text id="text3"><textPath xlink:href="#MyPath">abcdefghijklmnopqrstuvwxyz</textPath></text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 603 B |
@ -56,6 +56,7 @@ fails == style-property-not-on-script-element-01.svg pass.svg
|
||||
== svg-in-foreignObject-02.xhtml svg-in-foreignObject-01-ref.xhtml # reuse -01-ref.xhtml
|
||||
random-if(MOZ_WIDGET_TOOLKIT=="gtk2") == text-font-weight-01.svg text-font-weight-01-ref.svg # bug 386713
|
||||
== text-in-link-01.svg text-in-link-01-ref.svg
|
||||
== text-scale-01.svg text-scale-01-ref.svg
|
||||
== text-style-01a.svg text-style-01-ref.svg
|
||||
== text-style-01b.svg text-style-01-ref.svg
|
||||
== text-style-01c.svg text-style-01-ref.svg
|
||||
|
14
layout/reftests/svg/text-scale-01-ref.svg
Normal file
14
layout/reftests/svg/text-scale-01-ref.svg
Normal file
@ -0,0 +1,14 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
|
||||
|
||||
<title>Reference for text scaling</title>
|
||||
|
||||
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=392233 -->
|
||||
|
||||
<text x="0" y="100" font-size="100">Hello</text>
|
||||
<text x="0" y="200" font-size="100">Hello</text>
|
||||
<text x="0" y="300" font-size="100">Hello</text>
|
||||
</svg>
|
After Width: | Height: | Size: 448 B |
20
layout/reftests/svg/text-scale-01.svg
Normal file
20
layout/reftests/svg/text-scale-01.svg
Normal file
@ -0,0 +1,20 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
|
||||
|
||||
<title>Testcase for text scaling</title>
|
||||
|
||||
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=392233 -->
|
||||
|
||||
<g transform="scale(10)">
|
||||
<text x="0" y="10" font-size="10">Hello</text>
|
||||
</g>
|
||||
<g transform="scale(100)">
|
||||
<text x="0" y="2" font-size="1">Hello</text>
|
||||
</g>
|
||||
<g transform="scale(1000)">
|
||||
<text x="0" y="0.3" font-size="0.1">Hello</text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 555 B |
@ -46,9 +46,11 @@ class nsIDOMSVGPoint;
|
||||
class nsIDOMSVGRect;
|
||||
class nsSVGTextPathFrame;
|
||||
|
||||
// {2C466AED-CF7B-4479-A807-98151215A645}
|
||||
|
||||
// {ec9a9965-3ff2-4bb5-b0e2-dd8830e9f41a}
|
||||
#define NS_ISVGGLYPHFRAGMENTLEAF_IID \
|
||||
{ 0x2c466aed, 0xcf7b, 0x4479, { 0xa8, 0x7, 0x98, 0x15, 0x12, 0x15, 0xa6, 0x45 } }
|
||||
{ 0xec9a9965, 0x3ff2, 0x4bb5, \
|
||||
{ 0xb0, 0xe2, 0xdd, 0x88, 0x30, 0xe9, 0xf4, 0x1a } }
|
||||
|
||||
class nsISVGGlyphFragmentLeaf : public nsISVGGlyphFragmentNode
|
||||
{
|
||||
@ -70,8 +72,9 @@ public:
|
||||
enum { BASELINE_TEXT_BEFORE_EDGE = 6U };
|
||||
enum { BASELINE_TEXT_AFTER_EDGE = 7U };
|
||||
|
||||
NS_IMETHOD_(float) GetBaselineOffset(PRUint16 baselineIdentifier)=0;
|
||||
NS_IMETHOD_(float) GetAdvance()=0;
|
||||
NS_IMETHOD_(float) GetBaselineOffset(PRUint16 baselineIdentifier,
|
||||
PRBool aForceGlobalTransform)=0;
|
||||
NS_IMETHOD_(float) GetAdvance(PRBool aForceGlobalTransform)=0;
|
||||
|
||||
NS_IMETHOD_(void) SetGlyphPosition(float x, float y)=0;
|
||||
NS_IMETHOD_(nsSVGTextPathFrame*) FindTextPathParent()=0;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -44,11 +44,11 @@
|
||||
#include "nsISVGChildFrame.h"
|
||||
#include "gfxContext.h"
|
||||
#include "gfxFont.h"
|
||||
#include "gfxTextRunCache.h"
|
||||
|
||||
struct nsSVGCharacterPosition;
|
||||
class nsSVGTextFrame;
|
||||
class nsSVGGlyphFrame;
|
||||
class CharacterIterator;
|
||||
struct CharacterPosition;
|
||||
|
||||
typedef nsSVGGeometryFrame nsSVGGlyphFrameBase;
|
||||
|
||||
@ -61,8 +61,14 @@ class nsSVGGlyphFrame : public nsSVGGlyphFrameBase,
|
||||
nsIFrame* parentFrame, nsStyleContext* aContext);
|
||||
protected:
|
||||
nsSVGGlyphFrame(nsStyleContext* aContext)
|
||||
: nsSVGGlyphFrameBase(aContext),
|
||||
mWhitespaceHandling(COMPRESS_WHITESPACE) {}
|
||||
: nsSVGGlyphFrameBase(aContext),
|
||||
mTextRun(nsnull),
|
||||
mWhitespaceHandling(COMPRESS_WHITESPACE)
|
||||
{}
|
||||
~nsSVGGlyphFrame()
|
||||
{
|
||||
ClearTextRun();
|
||||
}
|
||||
|
||||
public:
|
||||
// nsISupports interface:
|
||||
@ -107,10 +113,13 @@ public:
|
||||
#endif
|
||||
|
||||
// nsISVGChildFrame interface:
|
||||
// These four always use the global transform, even if NS_STATE_NONDISPLAY_CHILD
|
||||
NS_IMETHOD PaintSVG(nsSVGRenderState *aContext, nsRect *aDirtyRect);
|
||||
NS_IMETHOD GetFrameForPointSVG(float x, float y, nsIFrame** hit);
|
||||
NS_IMETHOD_(nsRect) GetCoveredRegion();
|
||||
NS_IMETHOD UpdateCoveredRegion();
|
||||
NS_IMETHOD GetBBox(nsIDOMSVGRect **_retval);
|
||||
|
||||
NS_IMETHOD_(nsRect) GetCoveredRegion();
|
||||
NS_IMETHOD InitialUpdate();
|
||||
virtual void NotifySVGChanged(PRUint32 aFlags);
|
||||
NS_IMETHOD NotifyRedrawSuspended();
|
||||
@ -118,7 +127,6 @@ public:
|
||||
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate) { return NS_OK; }
|
||||
NS_IMETHOD SetOverrideCTM(nsIDOMSVGMatrix *aCTM) { return NS_ERROR_FAILURE; }
|
||||
virtual already_AddRefed<nsIDOMSVGMatrix> GetOverrideCTM() { return nsnull; }
|
||||
NS_IMETHOD GetBBox(nsIDOMSVGRect **_retval);
|
||||
NS_IMETHOD_(PRBool) IsDisplayContainer() { return PR_FALSE; }
|
||||
NS_IMETHOD_(PRBool) HasValidCoveredRect() { return PR_TRUE; }
|
||||
|
||||
@ -127,12 +135,22 @@ public:
|
||||
virtual nsresult UpdateGraphic(PRBool suppressInvalidation = PR_FALSE);
|
||||
|
||||
// nsISVGGlyphFragmentLeaf interface:
|
||||
// These do not use the global transform if NS_STATE_NONDISPLAY_CHILD
|
||||
NS_IMETHOD GetStartPositionOfChar(PRUint32 charnum, nsIDOMSVGPoint **_retval);
|
||||
NS_IMETHOD GetEndPositionOfChar(PRUint32 charnum, nsIDOMSVGPoint **_retval);
|
||||
NS_IMETHOD GetExtentOfChar(PRUint32 charnum, nsIDOMSVGRect **_retval);
|
||||
NS_IMETHOD GetRotationOfChar(PRUint32 charnum, float *_retval);
|
||||
NS_IMETHOD_(float) GetBaselineOffset(PRUint16 baselineIdentifier);
|
||||
NS_IMETHOD_(float) GetAdvance();
|
||||
/**
|
||||
* @param aForceGlobalTransform controls whether to use the
|
||||
* global transform even when NS_STATE_NONDISPLAY_CHILD
|
||||
*/
|
||||
NS_IMETHOD_(float) GetBaselineOffset(PRUint16 baselineIdentifier,
|
||||
PRBool aForceGlobalTransform);
|
||||
/**
|
||||
* @param aForceGlobalTransform controls whether to use the
|
||||
* global transform even when NS_STATE_NONDISPLAY_CHILD
|
||||
*/
|
||||
NS_IMETHOD_(float) GetAdvance(PRBool aForceGlobalTransform);
|
||||
|
||||
NS_IMETHOD_(void) SetGlyphPosition(float x, float y);
|
||||
NS_IMETHOD_(nsSVGTextPathFrame*) FindTextPathParent();
|
||||
@ -147,6 +165,7 @@ public:
|
||||
NS_IMETHOD_(PRBool) IsAbsolutelyPositioned();
|
||||
|
||||
// nsISVGGlyphFragmentNode interface:
|
||||
// These do not use the global transform if NS_STATE_NONDISPLAY_CHILD
|
||||
NS_IMETHOD_(PRUint32) GetNumberOfChars();
|
||||
NS_IMETHOD_(float) GetComputedTextLength();
|
||||
NS_IMETHOD_(float) GetSubStringLength(PRUint32 charnum, PRUint32 fragmentChars);
|
||||
@ -156,66 +175,47 @@ public:
|
||||
NS_IMETHOD_(void) SetWhitespaceHandling(PRUint8 aWhitespaceHandling);
|
||||
|
||||
protected:
|
||||
struct nsSVGCharacterPosition {
|
||||
gfxPoint pos;
|
||||
gfxFloat angle;
|
||||
PRBool draw;
|
||||
};
|
||||
friend class CharacterIterator;
|
||||
|
||||
// VC6 does not allow the inner class to access protected members
|
||||
// of the outer class
|
||||
class nsSVGAutoGlyphHelperContext;
|
||||
friend class nsSVGAutoGlyphHelperContext;
|
||||
|
||||
// A helper class to deal with gfxTextRuns and temporary thebes
|
||||
// contexts.
|
||||
class nsSVGAutoGlyphHelperContext
|
||||
{
|
||||
public:
|
||||
nsSVGAutoGlyphHelperContext(nsSVGGlyphFrame *aSource,
|
||||
const nsString &aText)
|
||||
{
|
||||
Init(aSource, aText);
|
||||
}
|
||||
|
||||
nsSVGAutoGlyphHelperContext(nsSVGGlyphFrame *aSource,
|
||||
const nsString &aText,
|
||||
nsSVGCharacterPosition **cp);
|
||||
|
||||
gfxContext *GetContext() { return mCT; }
|
||||
gfxTextRun *GetTextRun() { return mTextRun.get(); }
|
||||
|
||||
private:
|
||||
void Init(nsSVGGlyphFrame *aSource, const nsString &aText);
|
||||
|
||||
nsRefPtr<gfxContext> mCT;
|
||||
gfxTextRunCache::AutoTextRun mTextRun;
|
||||
};
|
||||
|
||||
// The textrun must be released via gfxTextRunCache::AutoTextRun
|
||||
gfxTextRun *GetTextRun(gfxContext *aCtx,
|
||||
const nsString &aText);
|
||||
// Use a power of 2 here. It's not so important to match
|
||||
// nsIDeviceContext::AppUnitsPerDevPixel, but since we do a lot of
|
||||
// multiplying by 1/GetTextRunUnitsFactor, it's good for it to be a
|
||||
// power of 2 to avoid accuracy loss.
|
||||
static PRUint32 GetTextRunUnitsFactor() { return 64; }
|
||||
|
||||
/**
|
||||
* @aParam aDrawScale font drawing must be scaled into user units
|
||||
* by this factor
|
||||
* @param aMetricsScale font metrics must be scaled into user units
|
||||
* by this factor
|
||||
* @param aForceGlobalTransform set to true if we should force use of
|
||||
* the global transform; otherwise we won't use the global transform
|
||||
* if we're a NONDISPLAY_CHILD
|
||||
*/
|
||||
PRBool EnsureTextRun(float *aDrawScale, float *aMetricsScale,
|
||||
PRBool aForceGlobalTransform);
|
||||
void ClearTextRun();
|
||||
|
||||
PRBool GetCharacterData(nsAString & aCharacterData);
|
||||
nsresult GetCharacterPosition(gfxContext *aContext,
|
||||
const nsString &aText,
|
||||
nsSVGCharacterPosition **aCharacterPosition);
|
||||
PRBool GetCharacterPositions(nsTArray<CharacterPosition>* aCharacterPositions,
|
||||
float aMetricsScale);
|
||||
|
||||
enum FillOrStroke { FILL, STROKE};
|
||||
|
||||
void LoopCharacters(gfxContext *aCtx, const nsString &aText,
|
||||
const nsSVGCharacterPosition *aCP,
|
||||
FillOrStroke aFillOrStroke);
|
||||
void AddCharactersToPath(CharacterIterator *aIter,
|
||||
gfxContext *aContext);
|
||||
void AddBoundingBoxesToPath(CharacterIterator *aIter,
|
||||
gfxContext *aContext);
|
||||
void FillCharacters(CharacterIterator *aIter,
|
||||
gfxContext *aContext);
|
||||
|
||||
void UpdateGeometry(PRBool bRedraw, PRBool suppressInvalidation);
|
||||
void UpdateMetrics();
|
||||
PRBool ContainsPoint(float x, float y);
|
||||
nsresult GetGlobalTransform(gfxContext *aContext);
|
||||
PRBool GetGlobalTransform(gfxMatrix *aContext);
|
||||
nsresult GetHighlight(PRUint32 *charnum, PRUint32 *nchars,
|
||||
nscolor *foreground, nscolor *background);
|
||||
|
||||
nsRefPtr<gfxFontGroup> mFontGroup;
|
||||
nsAutoPtr<gfxFontStyle> mFontStyle;
|
||||
// Owning pointer, must call gfxTextRunWordCache::RemoveTextRun before deleting
|
||||
gfxTextRun *mTextRun;
|
||||
gfxPoint mPosition;
|
||||
PRUint8 mWhitespaceHandling;
|
||||
};
|
||||
|
@ -73,15 +73,6 @@ NS_NewSVGTextFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsStyleContex
|
||||
//----------------------------------------------------------------------
|
||||
// nsIFrame methods
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGTextFrame::SetInitialChildList(nsIAtom* aListName,
|
||||
nsIFrame* aChildList)
|
||||
{
|
||||
nsresult rv = nsSVGTextFrameBase::SetInitialChildList(aListName, aChildList);
|
||||
NotifyGlyphMetricsChange();
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGTextFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
@ -127,7 +118,7 @@ nsSVGTextFrame::GetType() const
|
||||
NS_IMETHODIMP
|
||||
nsSVGTextFrame::GetNumberOfChars(PRInt32 *_retval)
|
||||
{
|
||||
UpdateGlyphPositioning();
|
||||
UpdateGlyphPositioning(PR_FALSE);
|
||||
|
||||
return nsSVGTextFrameBase::GetNumberOfChars(_retval);
|
||||
}
|
||||
@ -135,7 +126,7 @@ nsSVGTextFrame::GetNumberOfChars(PRInt32 *_retval)
|
||||
NS_IMETHODIMP
|
||||
nsSVGTextFrame::GetComputedTextLength(float *_retval)
|
||||
{
|
||||
UpdateGlyphPositioning();
|
||||
UpdateGlyphPositioning(PR_FALSE);
|
||||
|
||||
return nsSVGTextFrameBase::GetComputedTextLength(_retval);
|
||||
}
|
||||
@ -143,7 +134,7 @@ nsSVGTextFrame::GetComputedTextLength(float *_retval)
|
||||
NS_IMETHODIMP
|
||||
nsSVGTextFrame::GetSubStringLength(PRUint32 charnum, PRUint32 nchars, float *_retval)
|
||||
{
|
||||
UpdateGlyphPositioning();
|
||||
UpdateGlyphPositioning(PR_FALSE);
|
||||
|
||||
return nsSVGTextFrameBase::GetSubStringLength(charnum, nchars, _retval);
|
||||
}
|
||||
@ -151,7 +142,7 @@ nsSVGTextFrame::GetSubStringLength(PRUint32 charnum, PRUint32 nchars, float *_re
|
||||
NS_IMETHODIMP
|
||||
nsSVGTextFrame::GetStartPositionOfChar(PRUint32 charnum, nsIDOMSVGPoint **_retval)
|
||||
{
|
||||
UpdateGlyphPositioning();
|
||||
UpdateGlyphPositioning(PR_FALSE);
|
||||
|
||||
return nsSVGTextFrameBase::GetStartPositionOfChar(charnum, _retval);
|
||||
}
|
||||
@ -159,7 +150,7 @@ nsSVGTextFrame::GetStartPositionOfChar(PRUint32 charnum, nsIDOMSVGPoint **_retva
|
||||
NS_IMETHODIMP
|
||||
nsSVGTextFrame::GetEndPositionOfChar(PRUint32 charnum, nsIDOMSVGPoint **_retval)
|
||||
{
|
||||
UpdateGlyphPositioning();
|
||||
UpdateGlyphPositioning(PR_FALSE);
|
||||
|
||||
return nsSVGTextFrameBase::GetEndPositionOfChar(charnum, _retval);
|
||||
}
|
||||
@ -167,7 +158,7 @@ nsSVGTextFrame::GetEndPositionOfChar(PRUint32 charnum, nsIDOMSVGPoint **_retval)
|
||||
NS_IMETHODIMP
|
||||
nsSVGTextFrame::GetExtentOfChar(PRUint32 charnum, nsIDOMSVGRect **_retval)
|
||||
{
|
||||
UpdateGlyphPositioning();
|
||||
UpdateGlyphPositioning(PR_FALSE);
|
||||
|
||||
return nsSVGTextFrameBase::GetExtentOfChar(charnum, _retval);
|
||||
}
|
||||
@ -175,7 +166,7 @@ nsSVGTextFrame::GetExtentOfChar(PRUint32 charnum, nsIDOMSVGRect **_retval)
|
||||
NS_IMETHODIMP
|
||||
nsSVGTextFrame::GetRotationOfChar(PRUint32 charnum, float *_retval)
|
||||
{
|
||||
UpdateGlyphPositioning();
|
||||
UpdateGlyphPositioning(PR_FALSE);
|
||||
|
||||
return nsSVGTextFrameBase::GetRotationOfChar(charnum, _retval);
|
||||
}
|
||||
@ -183,7 +174,7 @@ nsSVGTextFrame::GetRotationOfChar(PRUint32 charnum, float *_retval)
|
||||
NS_IMETHODIMP
|
||||
nsSVGTextFrame::GetCharNumAtPosition(nsIDOMSVGPoint *point, PRInt32 *_retval)
|
||||
{
|
||||
UpdateGlyphPositioning();
|
||||
UpdateGlyphPositioning(PR_FALSE);
|
||||
|
||||
return nsSVGTextFrameBase::GetCharNumAtPosition(point, _retval);
|
||||
}
|
||||
@ -225,7 +216,6 @@ NS_IMETHODIMP
|
||||
nsSVGTextFrame::NotifyRedrawUnsuspended()
|
||||
{
|
||||
mMetricsState = unsuspended;
|
||||
UpdateGlyphPositioning();
|
||||
|
||||
return nsSVGTextFrameBase::NotifyRedrawUnsuspended();
|
||||
}
|
||||
@ -252,10 +242,34 @@ nsSVGTextFrame::GetOverrideCTM()
|
||||
return matrix;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGTextFrame::PaintSVG(nsSVGRenderState* aContext, nsRect *aDirtyRect)
|
||||
{
|
||||
UpdateGlyphPositioning(PR_TRUE);
|
||||
|
||||
return nsSVGTextFrameBase::PaintSVG(aContext, aDirtyRect);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGTextFrame::GetFrameForPointSVG(float x, float y, nsIFrame** hit)
|
||||
{
|
||||
UpdateGlyphPositioning(PR_TRUE);
|
||||
|
||||
return nsSVGTextFrameBase::GetFrameForPointSVG(x, y, hit);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGTextFrame::UpdateCoveredRegion()
|
||||
{
|
||||
UpdateGlyphPositioning(PR_TRUE);
|
||||
|
||||
return nsSVGTextFrameBase::UpdateCoveredRegion();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGTextFrame::GetBBox(nsIDOMSVGRect **_retval)
|
||||
{
|
||||
UpdateGlyphPositioning();
|
||||
UpdateGlyphPositioning(PR_TRUE);
|
||||
|
||||
return nsSVGTextFrameBase::GetBBox(_retval);
|
||||
}
|
||||
@ -308,7 +322,6 @@ void
|
||||
nsSVGTextFrame::NotifyGlyphMetricsChange()
|
||||
{
|
||||
mPositioningDirty = PR_TRUE;
|
||||
UpdateGlyphPositioning();
|
||||
}
|
||||
|
||||
static void
|
||||
@ -332,7 +345,7 @@ GetSingleValue(nsISVGGlyphFragmentLeaf *fragment,
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGTextFrame::UpdateGlyphPositioning()
|
||||
nsSVGTextFrame::UpdateGlyphPositioning(PRBool aForceGlobalTransform)
|
||||
{
|
||||
if (mMetricsState == suspended || !mPositioningDirty)
|
||||
return;
|
||||
@ -425,7 +438,7 @@ nsSVGTextFrame::UpdateGlyphPositioning()
|
||||
float dx = 0.0f;
|
||||
nsCOMPtr<nsIDOMSVGLengthList> list = fragment->GetDx();
|
||||
GetSingleValue(fragment, list, &dx);
|
||||
chunkLength += dx + fragment->GetAdvance();
|
||||
chunkLength += dx + fragment->GetAdvance(aForceGlobalTransform);
|
||||
fragment = fragment->GetNextGlyphFragment();
|
||||
if (fragment && fragment->IsAbsolutelyPositioned())
|
||||
break;
|
||||
@ -452,10 +465,11 @@ nsSVGTextFrame::UpdateGlyphPositioning()
|
||||
GetSingleValue(fragment, list, &dy);
|
||||
}
|
||||
|
||||
float baseline_offset = fragment->GetBaselineOffset(baseline);
|
||||
float baseline_offset =
|
||||
fragment->GetBaselineOffset(baseline, aForceGlobalTransform);
|
||||
fragment->SetGlyphPosition(x + dx, y + dy - baseline_offset);
|
||||
|
||||
x += dx + fragment->GetAdvance();
|
||||
x += dx + fragment->GetAdvance(aForceGlobalTransform);
|
||||
y += dy;
|
||||
fragment = fragment->GetNextGlyphFragment();
|
||||
if (fragment && fragment->IsAbsolutelyPositioned())
|
||||
|
@ -52,12 +52,10 @@ protected:
|
||||
: nsSVGTextFrameBase(aContext),
|
||||
mMetricsState(unsuspended),
|
||||
mPropagateTransform(PR_TRUE),
|
||||
mPositioningDirty(PR_FALSE) {}
|
||||
mPositioningDirty(PR_TRUE) {}
|
||||
|
||||
public:
|
||||
// nsIFrame:
|
||||
NS_IMETHOD SetInitialChildList(nsIAtom* aListName,
|
||||
nsIFrame* aChildList);
|
||||
NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
PRInt32 aModType);
|
||||
@ -84,6 +82,11 @@ public:
|
||||
virtual void NotifySVGChanged(PRUint32 aFlags);
|
||||
NS_IMETHOD NotifyRedrawSuspended();
|
||||
NS_IMETHOD NotifyRedrawUnsuspended();
|
||||
// Override these four to ensure that UpdateGlyphPositioning is called
|
||||
// to bring glyph positions up to date
|
||||
NS_IMETHOD PaintSVG(nsSVGRenderState* aContext, nsRect *aDirtyRect);
|
||||
NS_IMETHOD GetFrameForPointSVG(float x, float y, nsIFrame** hit);
|
||||
NS_IMETHOD UpdateCoveredRegion();
|
||||
NS_IMETHOD GetBBox(nsIDOMSVGRect **_retval);
|
||||
|
||||
// nsSVGContainerFrame methods:
|
||||
@ -103,7 +106,12 @@ public:
|
||||
void NotifyGlyphMetricsChange();
|
||||
|
||||
private:
|
||||
void UpdateGlyphPositioning();
|
||||
/**
|
||||
* @param aForceGlobalTransform passed down to nsSVGGlyphFrames to
|
||||
* control whether they should use the global transform even when
|
||||
* NS_STATE_NONDISPLAY_CHILD
|
||||
*/
|
||||
void UpdateGlyphPositioning(PRBool aForceGlobalTransform);
|
||||
|
||||
nsCOMPtr<nsIDOMSVGMatrix> mCanvasTM;
|
||||
nsCOMPtr<nsIDOMSVGMatrix> mOverrideCTM;
|
||||
|
Loading…
x
Reference in New Issue
Block a user