Closed
Bug 569722
Opened 15 years ago
Closed 12 years ago
Firefox SVG support does not implement the textLength and lengthAdjust attribute functionality of <text> elements
Categories
(Core :: SVG, defect)
Core
SVG
Tracking
()
RESOLVED
FIXED
mozilla25
People
(Reporter: hkjunkie, Assigned: heycam)
References
()
Details
(Keywords: dev-doc-needed, feature, relnote, Whiteboard: [parity-ie][parity-chrome][parity-safari][parity-opera])
Attachments
(1 file, 2 obsolete files)
46.80 KB,
patch
|
longsonr
:
review+
|
Details | Diff | Splinter Review |
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.0.18) Gecko/2010020220 (CK-zz) Firefox/3.0.18 (.NET CLR 3.5.30729)
Build Identifier: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.3) Gecko/20100401 (CK-zz) Firefox/3.6.3 (.NET CLR 3.5.30729)
For SVG to be used as a viable alternative in industrial diagrams to CGM or the developing webCGM standard, it is vital that the textLength and lengthAdjust attributes of text elements be supported. SVG graphics not having the ability to have the author specify a region that is to be filled with the text, which leaves the rendering entirely to the client font availability, cripples the use of SVG for industrial engineering drawings where not only text placement but importantly, text extent and position, are critical to a diagram.
Reproducible: Always
Steps to Reproduce:
1.Load the example URL that test the functionality.
2.See that firefox does not render the text as it should.
Actual Results:
The text is not expanded nor compressed to fit within the space defined by the textLength attributes of the text elements. The PNG bitmap image on the right half of the page depicts how the text should look.
Expected Results:
The two images (the svg on the left and png on the right) to look similar in how the text fills out the space defined by the bar-markers. The blue text elements should match the length of the red line's below them in the SVG.
I did the due diligence of searching the bug list for textLength and found nothing.
![]() |
||
Updated•15 years ago
|
Status: UNCONFIRMED → NEW
Ever confirmed: true
Comment 1•15 years ago
|
||
I'm getting this error message in the js console, when trying to iterate through the properties of a textPath element:
Error: uncaught exception: [Exception... "Component returned failure code: 0x80004001 (NS_ERROR_NOT_IMPLEMENTED) [nsIDOMSVGTextContentElement.textLength]" nsresult: "0x80004001 (NS_ERROR_NOT_IMPLEMENTED)"
Updated•15 years ago
|
Comment 3•14 years ago
|
||
In this area we seem to lag behind our major competitors.
Tested with the current release versions (on Windows):
* IE 9
* Chrome 13
* Safari 5.1
* Opera 11.50
They all seem to more or less pass the W3C test at the URL
(with minor differences how they squeeze/stretch the text).
Whiteboard: [parity-ie][parity-chrome][parity-safari][parity-opera]
Comment 4•14 years ago
|
||
I'd like to add a vote to fix this. Firefox does lag other browsers on this and without it it is difficult to support full justified text. It is possible via absolute glyph positioning but this tends to look bad on some platforms like iOS.
Comment 5•12 years ago
|
||
Still badly needed for technical drawings and documentation where text alignment is important.
Assignee | ||
Comment 6•12 years ago
|
||
Here's a WIP patch I worked up today. The test case in the URL works, except that it sometimes wildly misplaces the glyphs. I think this is due to the same underlying issues as bug 854286, where the <object> begins lift at a very small size, we reflow the text, getting a large mFontSizeScaleFactor, then the <object> is resized to its final size, but we don't reflow the text.
Maybe we can add a new NotifySVGChanged flag to indicate that the nsSVGOuterSVGFrame changed size.
No tests written yet.
Assignee: nobody → cam
Status: NEW → ASSIGNED
Assignee | ||
Updated•12 years ago
|
Assignee | ||
Comment 7•12 years ago
|
||
There are some question, though:
* what does it mean for some character positions to be specified, while using
textLength=""?
<text x="10 20 30" textLength="100">abcdef</text>
I think we could say that if we were to insert a gap of n user units between
each glyph without the "20 30", then we would do the same with the "20 30" there
but only between "cd" "de" and "ef".
* what does it mean for textLength="" to be used on a <tspan> at the same time
as on the <text>?
<text textLength="100">abc<tspan textLengt="50">def</tspan></text>
That could get complicated when bidi text is involved. I think I'd be happy
supporting textLength="" only on the <text> and not on descendent text content
elements.
Comment 8•12 years ago
|
||
Comment on attachment 771218 [details] [diff] [review]
WIP (v0.1)
>+nsSVGEnum*
>+nsSVGElement::GetAnimatedEnumeration(nsIAtom* aAttrName)
>+{
>+ EnumAttributesInfo info = GetEnumInfo();
>+ for (uint32_t i = 0; i < info.mEnumCount; i++) {
>+ if (aAttrName == *info.mEnumInfo[i].mName) {
>+ return &info.mEnums[i];
>+ }
>+ }
>+ NS_ABORT_IF_FALSE(false, "no matching length found");
no matching enum found
Comment 9•12 years ago
|
||
(In reply to Cameron McCormack (:heycam) from comment #7)
> There are some question, though:
>
>
> * what does it mean for textLength="" to be used on a <tspan> at the same
> time
> as on the <text>?
>
> <text textLength="100">abc<tspan textLengt="50">def</tspan></text>
>
> That could get complicated when bidi text is involved. I think I'd be
> happy
> supporting textLength="" only on the <text> and not on descendent text
> content
> elements.
I would think if there were textlengths on both text and tspan that the tspan textlength would just override the textlength on the text tag. Wow that's a mouthful.
Comment 10•12 years ago
|
||
<text x="10 20 30" textLength="100">abcdef</text>
Since we're ignoring the advances for the first 3 characters they get placed as if there was no textLength. We just scale the advances for the def positioning (but we calculate the scale as the total advances for all the text based on the font data).
<text textLength="100">abc<tspan textLengt="50">def</tspan></text>
So the tspan textLength is 50 which means that the abc advance values must total 100 - 50 as the def advance textLength sums to 50. If the text textLength < sum of child textLengths then presumably we ignore the textLength value.
Assignee | ||
Comment 11•12 years ago
|
||
Updated to fix the problem with <object>. We now reflow the text whenever our context scale changes by more than a factor of two since we last computed mFontSizeScaleFactor.
Attachment #771218 -
Attachment is obsolete: true
Assignee | ||
Comment 12•12 years ago
|
||
(In reply to Robert Longson from comment #10)
> <text x="10 20 30" textLength="100">abcdef</text>
>
> Since we're ignoring the advances for the first 3 characters they get placed
> as if there was no textLength. We just scale the advances for the def
> positioning (but we calculate the scale as the total advances for all the
> text based on the font data).
OK, I think that's what is happening at the moment, though I haven't tested exactly.
> <text textLength="100">abc<tspan textLengt="50">def</tspan></text>
>
> So the tspan textLength is 50 which means that the abc advance values must
> total 100 - 50 as the def advance textLength sums to 50. If the text
> textLength < sum of child textLengths then presumably we ignore the
> textLength value.
This makes sense, but I just wonder whether it is worth supporting this. Is there really a good use case for it? I like the simplicity of just storing a single scale factor for the whole text (when using lengthAdjust="spacesAndGlyphs"), rather than potentially one per text frame or rendered run. For the glyph position adjustments when using lengthAdjust="spaces", we again would need to store the adjustment amount per text frame (or it might be easier to do per characters, since in DoGlyphPositioning we are just iterating over the mPositions array), rather than a single adjustment amount to add in to each eligible character position.
Comment 13•12 years ago
|
||
Could always have the tspan case as a follow up.
Assignee | ||
Comment 14•12 years ago
|
||
(In reply to Robert Longson from comment #13)
> Could always have the tspan case as a follow up.
Yeah, I think I'll leave it to later.
Assignee | ||
Comment 15•12 years ago
|
||
Added some tests and fixed a problem with the scale being applied in the wrong order relative to glyph rotation.
Attachment #771529 -
Attachment is obsolete: true
Attachment #771744 -
Flags: review?(longsonr)
Assignee | ||
Comment 16•12 years ago
|
||
Try run in progress: https://tbpl.mozilla.org/?tree=Try&rev=3d2bfc197b4b
Assignee | ||
Comment 17•12 years ago
|
||
I'll work on the reftest failures.
Comment 18•12 years ago
|
||
Comment on attachment 771744 [details] [diff] [review]
patch (v1)
>+nsSVGElement::EnumInfo SVGTextContentElement::sEnumInfo[1] =
>+{
>+ { &nsGkAtoms::lengthAdjust, sLengthAdjustMap, SVG_LENGTHADJUST_SPACING }
>+};
>+
>+nsSVGElement::LengthInfo SVGTextContentElement::sLengthInfo[1] =
>+{
>+ { &nsGkAtoms::textLength, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::XY }
>+};
>+
Should add a comment noting that this design will need adjusting if we want to support textLength on textPath elements as they already have length and enum attriubte and the GetEnumInfo and GetLengthInfo of SVGTextPathElement won't iterate over these properties. Note this in the follow up bug that tracks doing this for tspan/textPath too.
You get away with it for text (would be ok for tspan too) as that element doesn't have length or enum attributes.
>
>+nsSVGEnum*
>+nsSVGElement::GetAnimatedEnumeration(nsIAtom* aAttrName)
>+{
>+ EnumAttributesInfo info = GetEnumInfo();
>+ for (uint32_t i = 0; i < info.mEnumCount; i++) {
>+ if (aAttrName == *info.mEnumInfo[i].mName) {
>+ return &info.mEnums[i];
>+ }
>+ }
>+ NS_ABORT_IF_FALSE(false, "no matching enum found");
>+ return nullptr;
>+}
>+
You don't need this, you can just cast mContent to SVGTextContentElement in nsSVGTextFrame2 and access the enum value directly.
>
>+ nsSVGEnum* GetAnimatedEnumeration(nsIAtom* aAttrName);
As above
>+double
static double
>+GetContextScale(const gfxMatrix& aMatrix)
>+{
>+ // If the textLength="" attribute was specified, then we need ResolvePositions
>+ // to record that a new run starts with each glyph.
>+ nsSVGElement* element = static_cast<nsSVGElement*>(mContent);
Cast to SVGTextContentElement instead.
>+ nsSVGLength2* textLengthAttr =
>+ element->GetAnimatedLength(nsGkAtoms::textLength);
Then get the attribute directly from mContent to avoid iterating over all the attributes.
>+ bool adjustingTextLength = textLengthAttr->IsExplicitlySet();
>+ float expectedTextLength = textLengthAttr->GetAnimValue(element);
>+ if (adjustingTextLength) {
>+ nscoord frameWidth = GetFirstPrincipalChild()->GetRect().width;
>+ float actualTextLength =
>+ static_cast<float>(presContext->AppUnitsToGfxUnits(frameWidth) * factor);
>+
>+ uint16_t lengthAdjust =
>+ element->GetAnimatedEnumeration(nsGkAtoms::lengthAdjust)->GetAnimValue();
Just get the attribute from the textContent element directly via mContent. See above.
Would like to see some SMIL tests that animation of these properties works.
r=longsonr with above issues fixed.
Attachment #771744 -
Flags: review?(longsonr) → review+
Comment 19•12 years ago
|
||
One other thing... Will TextRenderedRun::GetCharNumAtPosition need adjusting to cope with these properties.
Assignee | ||
Comment 20•12 years ago
|
||
(In reply to Robert Longson from comment #19)
> One other thing... Will TextRenderedRun::GetCharNumAtPosition need adjusting
> to cope with these properties.
I think it shouldn't need to, as it calls GetTransformFromRunUserSpaceToUserSpace which I've changed to take textLength="" into account. I'll add a test for these SVG DOM methods.
Assignee | ||
Comment 21•12 years ago
|
||
Assignee | ||
Comment 22•12 years ago
|
||
Bug 890692 is the followup for these attributes on <altGlyph, <tspan> and <textPath>.
Comment 23•12 years ago
|
||
Status: ASSIGNED → RESOLVED
Closed: 12 years ago
Flags: in-testsuite+
Resolution: --- → FIXED
Target Milestone: --- → mozilla25
Comment 24•12 years ago
|
||
The current implementation of textLength doesn't take into account the dx attribute on child <tspan> elements. The spacing contributed by the dx should be re-scaled proportionally, i.e. a dx which represents 10% of its parent <text> element's width should represent 10% of that width after the parent <text> element is adjusted. Instead the absolute size of the space is never adjusted.
Right now, this is implemented correctly in the other major browsers, namely:
* IE 9
* Chrome 31
* Safari 7
So the FF implementation of textLength on <text> is not in true parity with these browsers.
Here's a simple test case, the two strings should be the same length:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<style>
text { font: 20px Verdana }
tspan { fill: red; font-weight: bold }
</style>
<text x="15" y="30">You are
<tspan dx="10">not</tspan>
a banana
</text>
<rect x="15" y="37" width="230" height="3" fill="green"/>
<text x="15" y="60" textLength="230">You are
<tspan dx="10">not</tspan>
a banana
</text>
</svg>
Flags: needinfo?(cam)
Comment 25•12 years ago
|
||
Please raise a new bug for this issue and Cc cam and me on it
Updated•12 years ago
|
Flags: needinfo?(cam)
Comment 26•12 years ago
|
||
Created bug 950110 for the issue with dx attribute on child <tspan> elements
Updated•10 years ago
|
Keywords: dev-doc-needed
You need to log in
before you can comment on or make changes to this bug.
Description
•