Closed Bug 311545 (svg-bidi) Opened 19 years ago Closed 11 years ago

Support the 'writing-mode', 'direction' and 'unicode-bidi' properties in SVG

Categories

(Core :: SVG, defect)

defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla25

People

(Reporter: sijproject, Unassigned)

References

()

Details

(Keywords: rtl, testcase, Whiteboard: [Input])

Attachments

(5 files)

User-Agent:       Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8b5) Gecko/20051006 Firefox/1.4.1
Build Identifier: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8b5) Gecko/20051006 Firefox/1.4.1

when viewing svg graphics containing hebrew (and I guess other RTL languages)
text, the characters are displayed in the wrong order (from left to right) as
seen in the following URL : 
http://welcome.linux.org.il/welcome-to-linux-2004.svg
and
http://img100.imageshack.us/img100/9829/svgbidi8hv.png

however, the order of the chars should be as seen here:
http://img98.imageshack.us/img98/6716/good6wq.png

the problem is in the blue hebrew text. instead of seeing:
ברוכים הבאים ללינוקס
you see:
סקונילל םיאבא םיכורב

Reproducible: Always

Steps to Reproduce:
1. open an SVG file conataining RTL text
2. see the RTL text rendered as if it is an LTR text.
Actual Results:  
the image contains strings rendered left to right.

Expected Results:  
the strings should be rendered right to left instead.

using Firefox 1.5Beta2, downloaded from mozilla.org (not from my linux distro).
Assignee: nobody → general
Component: General → SVG
Product: Firefox → Core
QA Contact: general → ian
Version: unspecified → Trunk
FWIW, on OS X, I don't see any Hebrew at all on the linked SVG (due to font issues?)
Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b5) Gecko/20051006
Firefox/1.4.1 ID:2005100606
if relevant, there is no problem with win32 beta1, other than it looks much
smaller (about half the height and width) than the 2nd linked image.
Mozilla/5.0 (Windows; U; Windows NT 5.1; he; rv:1.8b4) Gecko/20050913 Firefox/1.4
for the above comment
Attached image updated testcase
I've changed the original testcase to make it more Hebrew-friendly. 

Things done: 
* changed the writing-mode to "rl" for right-to-left. Still, no luck.
* The font used changed from David CLM (culmus.sf.net - linux only) to more
known Arial (Microsoft; available at corefonts.sf.net).

While working on the file I've found that changing the font-family to serif or
sans-serif make the text disappear. Should I open separated bug about this
behavior?
I'm confirming the bug because it's well-reported and has a testcase (even
though i can't personally reproduce it on OS X).
Status: UNCONFIRMED → NEW
Ever confirmed: true
Keywords: testcase
(In reply to comment #2)
There is no problem with win32 1.5 beta 2 either.
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b5) Gecko/20051004
Firefox/1.4.1
Judging by the distribution of where people are seeing this and where they
aren't, it looks as if SVG is just sending the string directly to the platfrom
rendering layer without any kind of Bidi processing. On platforms with native
Bidi support the right-to-left text is displayed correctly; on platforms
without, it is displayed reversed.
*** Bug 324210 has been marked as a duplicate of this bug. ***
With regard to Simon's comment about native BIDI support, it is interesting to note that viewing the file http://geocities.com/urdutext/dial1.xml on IE with Adobe's plugin produces RTL Urdu text but the characters are not joined as they should be.
Flags: blocking1.9a2?
Flags: blocking1.9a2?
Flags: blocking1.9?
Would like to fix this for 1.9, but doubtful that we'll block for it.  Some notes on how this might be implemented are here:

  http://weblogs.mozillazine.org/roc/archives/2007/03/text_text_text.html
Flags: blocking1.9? → blocking1.9-
I assume it's not "wanted-1.9" because we're not in a position to make sure we allocate resources for it?
(In reply to comment #11)
> I assume it's not "wanted-1.9" because we're not in a position to make sure we
> allocate resources for it?

No, it wasn't "wanted-1.9" because I forget about that annotation.  I don't think that keyword has any relation to what resources are available.

Whiteboard: wanted-1.9
Whiteboard: wanted-1.9 → [wanted-1.9]
I'm supposed to work on a Ctrl+Tab tab switching panel for Firefox 3. I'm currently using SVG, and this bug hit me. The current version can be found at http://en.design-noir.de/mozilla/ctrl-tab/.
Blocks: 395980
Flags: wanted1.9+
Whiteboard: [wanted-1.9]
OS: Linux → All
Hardware: PC → All
Blocks: fx35-l10n-fa
No longer blocks: Persian-Fx3.5
Mass-assigning the new rtl keyword to RTL-related (see bug 349193).
Keywords: rtl
Google Have started producing SVG graphs in its Office Suite. Sadly, that feature is broken for some languages due to this Firefox bug. http://spreadsheets.google.com
See also comments in bug 402276
(In reply to comment #16)
> See also comments in bug 402276
> 

Dupe?
Dependent at most.
Depends on: 402276
No longer blocks: fx35-l10n-fa
No longer blocks: 395980
No longer depends on: 402276
Alias: svg-bidi
I tried to see if I can come up with a fix for it, and looked around the SVG code, but I couldn't find out where the text is actually rendered.  I expected to find the relevant code in either nsSVGTextFrame or nsSVGTextContainerFrame, but I didn't (and maybe I was looking in the wrong place).

Would fixing this involve in using something like nsLayoutUtils::DrawString for painting the text, or is it more involved than that?
Assignee: general → nobody
QA Contact: ian → general
Text in SVG is rendered in nsSVGGlyphFrame.

What will make this more involved is the possibility of sub-elements being split up by bidi reordering. See http://weblogs.mozillazine.org/roc/archives/2007/03/text_text_text.html and bug 402276 comment 4 and following for some discussion.
Thanks for the pointers.

So, here is what needs to be done, I think (please correct me if I'm wrong):

* Derive a bidi processor class from nsBidiPresUtils::BidiProcessor to handle the bidi processing and generation of textruns.
* Replace the mTextRun member with an array of text runs and populate this array in nsSVGGlyphFrame::EnsureTextRun by calling the bidi processor's ProcessText function with nsBidiPresUtils::MODE_MEASURE.
* Store a data structure in the bidi processor which maps indexes in the SVG text to indexes in specific text runs, so that we always know that the n'th character in the SVG text corresponds to the i'th character in the j'th textrun.
* Anywhere in nsSVGGlyphFrame where mTextRun is being used to figure out a dimension, use the map to get the dimension from the appropriate text run(s).
* Anywhere in nsSVGGlyphFrame where mTextRun is being used to draw the text, use the map to draw the appropriate text run(s).

Am I on the right track?
It's more complicated than that because the bidi processing needs to be done for the entire collection of nsSVGGlyphFrames which have a common nsSVGTextFrame ancestor.
(In reply to comment #24)
> It's more complicated than that because the bidi processing needs to be done
> for the entire collection of nsSVGGlyphFrames which have a common
> nsSVGTextFrame ancestor.

What causes a piece of text to be broken into several nsSVGGlyphFrames?  In other words, what constitutes the boundary for each nsSVGGlyphFrame?  I couldn't find the code responsible for constructing individual nsSVGGlyphFrames inside nsSVGTextFrame...
One nsSVGGlyphFrame is created for each text node.

The problem is stuff like this:

<text>Eng<tspan>lish HEB</tspan>REW</text>

After bidi reordering you get something that renders as

<text>Eng<tspan>lish </tspan>WER<tspan>BEH</tspan></text>
Keep in mind that the <tspan> may have its own style. So you really need to gather up all the text, perform bidi processing, and then place and paint the text in the appropriate styles. We'd have to stop keeping "covered regions" for individual glyph and span frames, since there can now be more than one region for a single frame. It's a mess.

An alternative would be to stop creating SVG frames for the contents of a <text>, and give it an anonymous block child and then create regular inline and text frames for <text> descendants. Then we can reflow the block as normal (well, not very normal, we'd need to use a reflow strategy like we do for foreignObject frames), but instead of rendering it normally, we could paint the <text> by walking the block frame subtree and extracting glyph positions and styles. We can't render the block normally because sometimes SVG text is rendered along a path... hit-testing and the SVG text DOM APIs would have to be modified to match. This is a fairly large project.
(In reply to comment #26)
> One nsSVGGlyphFrame is created for each text node.
> 
> The problem is stuff like this:
> 
> <text>Eng<tspan>lish HEB</tspan>REW</text>
> 
> After bidi reordering you get something that renders as
> 
> <text>Eng<tspan>lish </tspan>WER<tspan>BEH</tspan></text>

Are SVG tspan's supposed to work similar to HTML span's?  I guess not, because they can be positioned anywhere.  (And on a similar note, should Arabic joining work across tspan boundaries or not?)

So if I understand this correctly, currently one text run is created per each <text> element, and for painting the text, the individual characters are iterated over and each one is rendered with its own style (which may be inherited from a <tspan>).  Is that correct?

And I don't understand why after bidi processing your sample would look like the result you mentioned.

(In reply to comment #27)
> Keep in mind that the <tspan> may have its own style. So you really need to
> gather up all the text, perform bidi processing, and then place and paint the
> text in the appropriate styles. We'd have to stop keeping "covered regions" for
> individual glyph and span frames, since there can now be more than one region
> for a single frame. It's a mess.

I'm not sure about the covered regions, but the first part kind of makes sense (see my comments above though).  Does the SVG spec say anything about how bidi resolution is supposed to work?  Or are there any reference implementations available which can be trusted to have implemented bidi resolution in SVG correctly?

> An alternative would be to stop creating SVG frames for the contents of a
> <text>, and give it an anonymous block child and then create regular inline and
> text frames for <text> descendants. Then we can reflow the block as normal
> (well, not very normal, we'd need to use a reflow strategy like we do for
> foreignObject frames), but instead of rendering it normally, we could paint the
> <text> by walking the block frame subtree and extracting glyph positions and
> styles. We can't render the block normally because sometimes SVG text is
> rendered along a path... hit-testing and the SVG text DOM APIs would have to be
> modified to match. This is a fairly large project.

I don't understand most of this paragraph...  :-)
Another suggestion (which may be stupid!):  Can CharacterIterator be changed in a way that iterates over the string with the visual order (performing bidi resolution on the fly), so that the characters would be painted in the correct order by the same code which is painting them now?
(In reply to comment #28)
> Are SVG tspan's supposed to work similar to HTML span's?  I guess not, because
> they can be positioned anywhere.

So can HTML spans actually, via position:relative...

> (And on a similar note, should Arabic
> joining work across tspan boundaries or not?)

Yes, if possible.

> So if I understand this correctly, currently one text run is created per each
> <text> element, and for painting the text, the individual characters are
> iterated over and each one is rendered with its own style (which may be
> inherited from a <tspan>).  Is that correct?

Currently one text run is created per DOM text node. Shaping does not work correctly across span boundaries in SVG at the moment (it does in regular text).

> And I don't understand why after bidi processing your sample would look like
> the result you mentioned.

I'll attach a testcase.

> (In reply to comment #27)
> > Keep in mind that the <tspan> may have its own style. So you really need to
> > gather up all the text, perform bidi processing, and then place and paint
> > the text in the appropriate styles. We'd have to stop keeping "covered
> > regions" for individual glyph and span frames, since there can now be more
> > than one region for a single frame. It's a mess.
> 
> I'm not sure about the covered regions, but the first part kind of makes sense
> (see my comments above though).  Does the SVG spec say anything about how bidi
> resolution is supposed to work?  Or are there any reference implementations
> available which can be trusted to have implemented bidi resolution in SVG
> correctly?

I think it's fairly simple: SVG text content should behave just like the corresponding HTML content, when SVG-specific features are not present.

> > An alternative would be to stop creating SVG frames for the contents of a
> > <text>, and give it an anonymous block child and then create regular inline
> > and text frames for <text> descendants. Then we can reflow the block as
> > normal (well, not very normal, we'd need to use a reflow strategy like we
> > do for foreignObject frames), but instead of rendering it normally, we
> > could paint the <text> by walking the block frame subtree and extracting
> > glyph positions and styles. We can't render the block normally because
> > sometimes SVG text is rendered along a path... hit-testing and the SVG text
> > DOM APIs would have to be modified to match. This is a fairly large project.
> 
> I don't understand most of this paragraph...  :-)

OK, let me try to simplify:
1) create frames for SVG <text> and its descendants as if it was the corresponding CSS-formatted HTML
2) use our regular HTML/CSS text engine to lay out the text
3) when painting an SVG <text>, don't paint the child (HTML-ish) frames normally. Instead, walk the frame subtree, extract the glyph positions and styles, and render the glyphs the SVG way.

That gives you a lot of features "for free": full CSS formatting, bidi resolution, textrun construction and management, including text shaping across span boundaries.
(In reply to comment #30)
> (In reply to comment #28)
> > Are SVG tspan's supposed to work similar to HTML span's?  I guess not, because
> > they can be positioned anywhere.
> 
> So can HTML spans actually, via position:relative...

Yes, you're right.  In order to convince myself, I tried this:

data:text/html;charset=utf-8,<div>Eng<span style="position: relative; top: 20px;">lish פרק</span>ליטו</div>

Although I should confess that I have never seen anything like this on the web before.  :-)

And for more fun, Arabic joining works there as well!

data:text/html;charset=utf-8,<div>Eng<span style="position: relative; top: 20px;">lish فای</span>رفاکس</div>

> > (And on a similar note, should Arabic
> > joining work across tspan boundaries or not?)
> 
> Yes, if possible.

Actually, in the current implementation, Arabic joining works correctly (well, the letters are correctly shaped, but from left to right).

> > So if I understand this correctly, currently one text run is created per each
> > <text> element, and for painting the text, the individual characters are
> > iterated over and each one is rendered with its own style (which may be
> > inherited from a <tspan>).  Is that correct?
> 
> Currently one text run is created per DOM text node. Shaping does not work
> correctly across span boundaries in SVG at the moment (it does in regular
> text).

Is there a bug filed on that?  If not, I'll file one.

> > And I don't understand why after bidi processing your sample would look like
> > the result you mentioned.
> 
> I'll attach a testcase.

Yeah, I see now.  For the HTML case, do we actually create separate <b> elements (or frames)?  Where does this magic happen, inside nsBidiPresUtils::ProcessText?

> > (In reply to comment #27)
> > I'm not sure about the covered regions, but the first part kind of makes sense
> > (see my comments above though).  Does the SVG spec say anything about how bidi
> > resolution is supposed to work?  Or are there any reference implementations
> > available which can be trusted to have implemented bidi resolution in SVG
> > correctly?
> 
> I think it's fairly simple: SVG text content should behave just like the
> corresponding HTML content, when SVG-specific features are not present.

Right.

> OK, let me try to simplify:
> 1) create frames for SVG <text> and its descendants as if it was the
> corresponding CSS-formatted HTML
> 2) use our regular HTML/CSS text engine to lay out the text
> 3) when painting an SVG <text>, don't paint the child (HTML-ish) frames
> normally. Instead, walk the frame subtree, extract the glyph positions and
> styles, and render the glyphs the SVG way.
> 
> That gives you a lot of features "for free": full CSS formatting, bidi
> resolution, textrun construction and management, including text shaping across
> span boundaries.

Thanks for the explanation.  I'm currently busy on some private browsing stuff which needs to be done for 1.9.1, but I will revisit it post-1.9.1, and try to implement this solution.
Assignee: nobody → ehsan.akhgari
(In reply to comment #32)
> (In reply to comment #30)
> > Currently one text run is created per DOM text node. Shaping does not work
> > correctly across span boundaries in SVG at the moment (it does in regular
> > text).
> 
> Is there a bug filed on that?  If not, I'll file one.

I don't know, but there's not much point in filing a new bug if we fix it here.

> > I'll attach a testcase.
> 
> Yeah, I see now.  For the HTML case, do we actually create separate <b>
> elements (or frames)?  Where does this magic happen, inside
> nsBidiPresUtils::ProcessText?

We create separate frames, in nsBidiPresUtils::Resolve.

> > OK, let me try to simplify:
> > 1) create frames for SVG <text> and its descendants as if it was the
> > corresponding CSS-formatted HTML
> > 2) use our regular HTML/CSS text engine to lay out the text
> > 3) when painting an SVG <text>, don't paint the child (HTML-ish) frames
> > normally. Instead, walk the frame subtree, extract the glyph positions and
> > styles, and render the glyphs the SVG way.
> > 
> > That gives you a lot of features "for free": full CSS formatting, bidi
> > resolution, textrun construction and management, including text shaping
> > across span boundaries.
> 
> Thanks for the explanation.  I'm currently busy on some private browsing stuff
> which needs to be done for 1.9.1, but I will revisit it post-1.9.1, and try to
> implement this solution.

Yeah, I've flipflopped back and forth about which way is better, and I currently think this is the best way. We will probably have to put in some SVG-specific paths to the core text code --- mainly disabling features that shouldn't work in SVG --- but hopefully not too much. This way is probably easier than doing more involved work.

Step 1 involves hacking on nsCSSFrameConstructor. You'll want to create an anonymous block child for the <text> element, much like we do for foreignObjects, then create inline frames and text frames for the descendants. The SVG <textPath> element will need special handling, it will need to be a direct child of the nsSVGTextFrame. Boris or I can help you with that.

Step 2 involves copying the way nsSVGOuterSVGFrame reflows nsSVGForeignObjectFrames.

Step 3 is basically a lot of changes to nsSVGTextFrame to reimplement all the functionality that's currently in nsSVGGlyphFrame and nsSVGTextContainerFrame. You'll need to understand the existing code there and we'll need to talk about how it can be reimplemented using the frame positions and glyph data that nsBlockFrame/nsInlineFrame/nsTextFrame store.
This file contains urdu text that should be rendered from right to left with character joining within a word. Currently, the text is rendered from left to right without character joining
This image shows correct and incorrect rendering of Urdu text
Blocks: svg11tests
Summary: rtl (like hebrew) text displayed incorrectly in svg rendering → Support the 'writing-mode', 'direction' and 'unicode-bidi' properties in SVG
Updating to reality: I won't have the time to work on this for the foreseeable future!
Assignee: ehsan.akhgari → nobody
Whiteboard: [Input]
Any progress on this issue?

I can still reproduce this issue on Firefox 3.6.12 , Linux. ( and Windows )
While Chrome 10.0.624 dev renders the text just fine.

Issue can be reproduce using this sample:
( Taken from the Moodle 2 codebase which uses YUI 3 javascript )

<svg version="1.1" height="40" width="26" id="yui_3_2_0_1_1296843600557316"><text font-size="10px" y="40" transform="rotate(270, 6.5, 33.5)" xml:lang="he" direction="rtl" fill="rgb(0, 0, 0)" id="yui_3_2_0_1_1296843600557319">הגדרות</text></svg>

The Hebrew text display backwards.
That example works in recent 4.0 betas, due to bug 620446.
The linked example (from my original report) works with Firefox 4.0 from Archlinux. also works fine on Firefox 4.0 on Android.
I also checked the Nadav's example.

I think the status can be changed to "Resolved" then.
I confirmed. Issue is solved for Firefox 4.0 (Kubuntu 11.4)
Simple cases work because of bug 620446, but this bug should stay open for a complete fix.
Bidirectional text in SVG with the new SVG text frames should work now.  I don't think the Inkscape rendering of the attached test is correct, though there were some changes to the SVG specification at some point in the last couple of years to make sure that the direction property is used to determine the direction of the entire <text> element.

If you find any other specific problems, please open new bugs.
Status: NEW → RESOLVED
Closed: 11 years ago
Depends on: svgtext, 839955
Resolution: --- → FIXED
Target Milestone: --- → mozilla25
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: