[webkit-dev] Fwd: Ruby Text Enhancements

David Hyatt hyatt at apple.com
Fri Sep 24 23:02:14 PDT 2010

On Sep 24, 2010, at 6:56 PM, Eric Mader wrote:

>> I have prototyped something that seems to more-or-less work. Here's what I did:
>> 1) Changed RenderRubyRun to subclass these methods:
>>     virtual int marginTop() const;
>>     virtual int marginBottom() const;
>>     virtual int marginLeft() const;
>>     virtual int marginRight() const;
>> 2) added these members to RenderRubyRun:
>>     mutable bool m_haveHorizontalMargins;
>>     mutable int m_leftMargin;
>>     mutable int m_rightMargin;
>> 3) Added this private method to  RenderRubyRun:
>>     void getHorizontalMargins() const;
>> 4) Here's what marginLeft() and MarginRight() look like:
>> int RenderRubyRun::marginLeft() const
>> {
>>     getHorizontalMargins();
>>     return m_leftMargin;
>> }
>> int RenderRubyRun::marginRight() const
>> {
>>     getHorizontalMargins();
>>     return m_rightMargin;
>> }
>> And here's getHorizontalMargins():
>> void RenderRubyRun::getHorizontalMargins() const
>> {
>>     if (m_haveHorizontalMargins) {
>>         return;
>>     }
>>     RenderText* rubyRenderText = static_cast<RenderText*> (rubyText()->firstChild());
>>     RenderText* baseRenderText = static_cast<RenderText*> (rubyBase()->firstChild());
>>     int rubyLength = rubyRenderText->firstTextBox()->width();
>>     int baseLength = baseRenderText->firstTextBox()->width();
>>     int leftMargin = RenderBlock::marginLeft();
>>     int rightMargin = RenderBlock::marginRight();
>>     if (baseLength < rubyLength) {
>>         RenderObject* prevSibling = parent()->previousSibling();
>>         RenderObject* nextSibling = parent()->nextSibling();
>>         bool prevIsText = prevSibling && prevSibling->isText();
>>         bool nextIsText = nextSibling && nextSibling->isText();
>>         // FIXME: handle odd difference?
>>         if (prevIsText)
>>             leftMargin += (baseLength - rubyLength) / 2;
>>         if (nextIsText)
>>             rightMargin += (baseLength - rubyLength) / 2;
>>     }
>>     m_leftMargin = leftMargin;
>>     m_rightMargin = rightMargin;
>>     m_haveHorizontalMargins = true;
>> }

It would probably be simpler to just subclass computeLogicalWidth (recently renamed from calcWidth) and modify the m_marginLeft and m_marginRight variables after calling the base class method.  Then you don't have to add any new member variables.

The big problem with building the overhang into margins at the initial calculation time, though, is that you may not get a relayout when objects around you change, so you won't get an opportunity to adjust your margins when that happens.  Your margins are also computed before you've even know what's going on the line, so it could be really tricky to have all the information you need.

It just doesn't seem like you can deal with all the corner cases without integrating right into line layout.  I don't see how else you can know if you have adequate available space to actually overhang without knowing what you've seen so far on the line and how much space you have left on the line.

>> This method makes several assumptions that I'm not 100% sure are always safe:
>> * That a RenderRuby object holds only 1 RenderRubyRun object.

I believe you can have multiple RenderRubyRuns inside a single RenderRuby.


"The ruby element allows one or more spans of phrasing content to be marked with ruby annotations."

>> * That the text for the ruby text and ruby base are always the direct child of the RenderRubyText and RenderRubyBase object.

I doubt that's a valid assumption.  I assume that you can have a content tree of markup underneath a RenderRubyText and a RenderRubyBase, e.g., if you put in some <i> and some <b>.  Anyway, I think you could just ask for the width() of the rubyText() and rubyBase() objects themselves rather than drilling down into their subtrees.

>> * That the neighboring text is always a direct sibling of the RenderRuby object.

Not a valid assumption.  You could have empty spans etc.

>> One enhancement I know is needed is to look at successive neighboring objects to make sure that there's enough text there that the overhanging part of the ruby text doesn't overshoot the neighbor(s) as well and bump into something it can't overlap.
>> Does this general approach look right?

This is a tough problem.  It seems like you have to get involved in the line layout code e.g., findNextLineBreak in order to really do the right thing.  findNextLineBreak uses an iterator that walks the objects, so it's easier to tell what text came before you and what text comes after you.  You can also tell whether or not that text will even fit on the line and possibly do the margin hacking there.

You may not want to overhang either if the surrounding text has a higher ascent, since I assume you don't want to have the ruby overlapping some taller adjacent text.

(hyatt at apple.com)

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.webkit.org/pipermail/webkit-dev/attachments/20100925/bba77f60/attachment.html>

More information about the webkit-dev mailing list