Changeset 70263 in webkit


Ignore:
Timestamp:
Oct 21, 2010 2:16:55 PM (14 years ago)
Author:
hyatt@apple.com
Message:

https://bugs.webkit.org/show_bug.cgi?id=48085

Reviewed by Darin Adler.

Make basic vertical text painting work. This includes the text itself, underlines, overlines, line-throughs and shadows.

Added fast/blockflow/english-lr-text.html

WebCore:

  • rendering/InlineFlowBox.cpp:

(WebCore::InlineFlowBox::paint):

  • rendering/InlineFlowBox.h:
  • rendering/InlineTextBox.cpp:

(WebCore::InlineTextBox::applyShadowToGraphicsContext):
(WebCore::paintTextWithShadows):
(WebCore::InlineTextBox::paint):
(WebCore::InlineTextBox::paintDecoration):
(WebCore::InlineTextBox::paintTextMatchMarker):

  • rendering/InlineTextBox.h:
  • rendering/svg/SVGInlineTextBox.cpp:

(WebCore::SVGInlineTextBox::paintTextWithShadows):

LayoutTests:

  • fast/blockflow/english-lr-text.html: Added.
  • platform/mac/fast/blockflow/english-lr-text-expected.checksum: Added.
  • platform/mac/fast/blockflow/english-lr-text-expected.png: Added.
  • platform/mac/fast/blockflow/english-lr-text-expected.txt: Added.
Location:
trunk
Files:
4 added
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r70260 r70263  
     12010-10-21  David Hyatt  <hyatt@apple.com>
     2
     3        Reviewed by Darin Adler.
     4
     5        https://bugs.webkit.org/show_bug.cgi?id=48085
     6
     7        Make basic vertical text painting work.  This includes the text itself, underlines, overlines, line-throughs and shadows.
     8
     9        Added fast/blockflow/english-lr-text.html
     10
     11        * fast/blockflow/english-lr-text.html: Added.
     12        * platform/mac/fast/blockflow/english-lr-text-expected.checksum: Added.
     13        * platform/mac/fast/blockflow/english-lr-text-expected.png: Added.
     14        * platform/mac/fast/blockflow/english-lr-text-expected.txt: Added.
     15
    1162010-10-21  James Robinson  <jamesr@chromium.org>
    217
  • trunk/LayoutTests/platform/mac/fast/text/international/vertical-text-glyph-test-expected.checksum

    r70250 r70263  
    1 83a57acedeb979e93959cf59fe59cdfc
     1386f323eb617f371186afe888df1ce4e
  • trunk/WebCore/ChangeLog

    r70262 r70263  
     12010-10-21  David Hyatt  <hyatt@apple.com>
     2
     3        Reviewed by Darin Adler.
     4
     5        https://bugs.webkit.org/show_bug.cgi?id=48085
     6
     7        Make basic vertical text painting work.  This includes the text itself, underlines, overlines, line-throughs and shadows.
     8
     9        Added fast/blockflow/english-lr-text.html
     10
     11        * rendering/InlineFlowBox.cpp:
     12        (WebCore::InlineFlowBox::paint):
     13        * rendering/InlineFlowBox.h:
     14        * rendering/InlineTextBox.cpp:
     15        (WebCore::InlineTextBox::applyShadowToGraphicsContext):
     16        (WebCore::paintTextWithShadows):
     17        (WebCore::InlineTextBox::paint):
     18        (WebCore::InlineTextBox::paintDecoration):
     19        (WebCore::InlineTextBox::paintTextMatchMarker):
     20        * rendering/InlineTextBox.h:
     21        * rendering/svg/SVGInlineTextBox.cpp:
     22        (WebCore::SVGInlineTextBox::paintTextWithShadows):
     23
    1242010-10-21  No'am Rosenthal  <noam.rosenthal@nokia.com>
    225
  • trunk/WebCore/WebCore.xcodeproj/project.pbxproj

    r70250 r70263  
    2120121201                        buildConfigurationList = 149C284308902B11008A9EFC /* Build configuration list for PBXProject "WebCore" */;
    2120221202                        compatibilityVersion = "Xcode 2.4";
     21203                        developmentRegion = English;
    2120321204                        hasScannedForEncodings = 1;
    2120421205                        knownRegions = (
  • trunk/WebCore/rendering/InlineFlowBox.cpp

    r70172 r70263  
    702702            return;
    703703        } else {
    704             // 1. Paint our background, border and box-shadow.
     704            // Paint our background, border and box-shadow.
    705705            paintBoxDecorations(paintInfo, tx, ty);
    706 
    707             // 2. Paint our underline and overline.
    708             paintTextDecorations(paintInfo, tx, ty, false);
    709706        }
    710707    }
     
    718715    childInfo.updatePaintingRootForChildren(renderer());
    719716   
    720     // 3. Paint our children.
     717    // Paint our children.
    721718    if (paintPhase != PaintPhaseSelfOutline) {
    722719        for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
     
    725722        }
    726723    }
    727 
    728     // 4. Paint our strike-through
    729     if (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)
    730         paintTextDecorations(paintInfo, tx, ty, true);
    731724}
    732725
     
    931924}
    932925
    933 static bool shouldDrawTextDecoration(RenderObject* obj)
    934 {
    935     for (RenderObject* curr = obj->firstChild(); curr; curr = curr->nextSibling()) {
    936         if (curr->isRenderInline())
    937             return true;
    938         if (curr->isText() && !curr->isBR()) {
    939             if (!curr->style()->collapseWhiteSpace())
    940                 return true;
    941             Node* currElement = curr->node();
    942             if (!currElement)
    943                 return true;
    944             if (!currElement->isTextNode())
    945                 return true;
    946             if (!static_cast<Text*>(currElement)->containsOnlyWhitespace())
    947                 return true;
    948         }
    949     }
    950     return false;
    951 }
    952 
    953 void InlineFlowBox::paintTextDecorations(PaintInfo& paintInfo, int tx, int ty, bool paintedChildren)
    954 {
    955     // Paint text decorations like underlines/overlines. We only do this if we aren't in quirks mode (i.e., in
    956     // almost-strict mode or strict mode).
    957     if (renderer()->document()->inQuirksMode() || !paintInfo.shouldPaintWithinRoot(renderer()) ||
    958         renderer()->style()->visibility() != VISIBLE)
    959         return;
    960    
    961     // We don't want underlines or other decorations when we're trying to draw nothing but the selection as white text.
    962     if (paintInfo.phase == PaintPhaseSelection && paintInfo.forceBlackText)
    963         return;
    964 
    965     GraphicsContext* context = paintInfo.context;
    966     tx += m_x;
    967     ty += m_y;
    968     RenderStyle* styleToUse = renderer()->style(m_firstLine);
    969     int deco = parent() ? styleToUse->textDecoration() : styleToUse->textDecorationsInEffect();
    970     if (deco != TDNONE &&
    971         ((!paintedChildren && ((deco & UNDERLINE) || (deco & OVERLINE))) || (paintedChildren && (deco & LINE_THROUGH))) &&
    972         shouldDrawTextDecoration(renderer())) {
    973         int x = m_x + borderLogicalLeft() + paddingLogicalLeft();
    974         int w = m_logicalWidth - (borderLogicalLeft() + paddingLogicalLeft() + borderLogicalRight() + paddingLogicalRight());
    975         RootInlineBox* rootLine = root();
    976         if (rootLine->ellipsisBox()) {
    977             int ellipsisX = m_x + rootLine->ellipsisBox()->x();
    978             int ellipsisWidth = rootLine->ellipsisBox()->logicalWidth();
    979             bool ltr = renderer()->style()->isLeftToRightDirection();
    980             if (rootLine == this) {
    981                 // Trim w and x so that the underline isn't drawn underneath the ellipsis.
    982                 // ltr: is our right edge farther right than the right edge of the ellipsis.
    983                 // rtl: is the left edge of our box farther left than the left edge of the ellipsis.
    984                 bool ltrTruncation = ltr && (x + w >= ellipsisX + ellipsisWidth);
    985                 bool rtlTruncation = !ltr && (x <= ellipsisX + ellipsisWidth);
    986                 if (ltrTruncation)
    987                     w -= (x + w) - (ellipsisX + ellipsisWidth);
    988                 else if (rtlTruncation) {
    989                     int dx = m_x - ((ellipsisX - m_x) + ellipsisWidth);
    990                     tx -= dx;
    991                     w += dx;
    992                 }
    993             } else {
    994                 bool ltrPastEllipsis = ltr && x >= ellipsisX;
    995                 bool rtlPastEllipsis = !ltr && (x + w) <= (ellipsisX + ellipsisWidth);
    996                 if (ltrPastEllipsis || rtlPastEllipsis)
    997                     return;
    998 
    999                 bool ltrTruncation = ltr && x + w >= ellipsisX;
    1000                 bool rtlTruncation = !ltr && x <= ellipsisX;
    1001                 if (ltrTruncation)
    1002                     w -= (x + w - ellipsisX);
    1003                 else if (rtlTruncation) {
    1004                     int dx = m_x - ((ellipsisX - m_x) + ellipsisWidth);
    1005                     tx -= dx;
    1006                     w += dx;
    1007                 }
    1008             }
    1009         }
    1010 
    1011         // We must have child boxes and have decorations defined.
    1012         tx += borderLogicalLeft() + paddingLogicalLeft();
    1013 
    1014         Color underline, overline, linethrough;
    1015         underline = overline = linethrough = styleToUse->visitedDependentColor(CSSPropertyColor);
    1016         if (!parent())
    1017             renderer()->getTextDecorationColors(deco, underline, overline, linethrough);
    1018 
    1019         bool isPrinting = renderer()->document()->printing();
    1020         context->setStrokeThickness(1.0f); // FIXME: We should improve this rule and not always just assume 1.
    1021 
    1022         bool paintUnderline = deco & UNDERLINE && !paintedChildren;
    1023         bool paintOverline = deco & OVERLINE && !paintedChildren;
    1024         bool paintLineThrough = deco & LINE_THROUGH && paintedChildren;
    1025 
    1026         bool linesAreOpaque = !isPrinting && (!paintUnderline || underline.alpha() == 255) && (!paintOverline || overline.alpha() == 255) && (!paintLineThrough || linethrough.alpha() == 255);
    1027 
    1028         int baselinePos = renderer()->style(m_firstLine)->font().ascent();
    1029         if (!isRootInlineBox())
    1030             baselinePos += boxModelObject()->borderTop() + boxModelObject()->paddingTop();
    1031 
    1032         bool setClip = false;
    1033         int extraOffset = 0;
    1034         const ShadowData* shadow = styleToUse->textShadow();
    1035         if (!linesAreOpaque && shadow && shadow->next()) {
    1036             IntRect clipRect(tx, ty, w, baselinePos + 2);
    1037             for (const ShadowData* s = shadow; s; s = s->next()) {
    1038                 IntRect shadowRect(tx, ty, w, baselinePos + 2);
    1039                 shadowRect.inflate(s->blur());
    1040                 shadowRect.move(s->x(), s->y());
    1041                 clipRect.unite(shadowRect);
    1042                 extraOffset = max(extraOffset, max(0, s->y()) + s->blur());
    1043             }
    1044             context->save();
    1045             context->clip(clipRect);
    1046             extraOffset += baselinePos + 2;
    1047             ty += extraOffset;
    1048             setClip = true;
    1049         }
    1050 
    1051         ColorSpace colorSpace = renderer()->style()->colorSpace();
    1052         bool setShadow = false;
    1053         do {
    1054             if (shadow) {
    1055                 if (!shadow->next()) {
    1056                     // The last set of lines paints normally inside the clip.
    1057                     ty -= extraOffset;
    1058                     extraOffset = 0;
    1059                 }
    1060                 context->setShadow(IntSize(shadow->x(), shadow->y() - extraOffset), shadow->blur(), shadow->color(), colorSpace);
    1061                 setShadow = true;
    1062                 shadow = shadow->next();
    1063             }
    1064 
    1065             if (paintUnderline) {
    1066                 context->setStrokeColor(underline, colorSpace);
    1067                 context->setStrokeStyle(SolidStroke);
    1068                 // Leave one pixel of white between the baseline and the underline.
    1069                 context->drawLineForText(IntPoint(tx, ty + baselinePos + 1), w, isPrinting);
    1070             }
    1071             if (paintOverline) {
    1072                 context->setStrokeColor(overline, colorSpace);
    1073                 context->setStrokeStyle(SolidStroke);
    1074                 context->drawLineForText(IntPoint(tx, ty), w, isPrinting);
    1075             }
    1076             if (paintLineThrough) {
    1077                 context->setStrokeColor(linethrough, colorSpace);
    1078                 context->setStrokeStyle(SolidStroke);
    1079                 context->drawLineForText(IntPoint(tx, ty + 2 * baselinePos / 3), w, isPrinting);
    1080             }
    1081         } while (shadow);
    1082 
    1083         if (setClip)
    1084             context->restore();
    1085         else if (setShadow)
    1086             context->clearShadow();
    1087     }
    1088 }
    1089 
    1090926InlineBox* InlineFlowBox::firstLeafChild() const
    1091927{
  • trunk/WebCore/rendering/InlineFlowBox.h

    r70172 r70263  
    9797    void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int w, int h, CompositeOperator = CompositeSourceOver);
    9898    void paintBoxShadow(GraphicsContext*, RenderStyle*, ShadowStyle, int tx, int ty, int w, int h);
    99     virtual void paintTextDecorations(PaintInfo&, int tx, int ty, bool paintedChildren = false);
    10099    virtual void paint(PaintInfo&, int tx, int ty);
    101100    virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty);
  • trunk/WebCore/rendering/InlineTextBox.cpp

    r70072 r70263  
    312312}
    313313
    314 FloatSize InlineTextBox::applyShadowToGraphicsContext(GraphicsContext* context, const ShadowData* shadow, const FloatRect& textRect, bool stroked, bool opaque)
     314FloatSize InlineTextBox::applyShadowToGraphicsContext(GraphicsContext* context, const ShadowData* shadow, const FloatRect& textRect, bool stroked, bool opaque, bool vertical)
    315315{
    316316    if (!shadow)
     
    318318
    319319    FloatSize extraOffset;
    320     FloatSize shadowOffset(shadow->x(), shadow->y());
     320    int shadowX = vertical ? shadow->y() : shadow->x();
     321    int shadowY = vertical ? -shadow->x() : shadow->y();
     322    FloatSize shadowOffset(shadowX, shadowY);
    321323    int shadowBlur = shadow->blur();
    322324    const Color& shadowColor = shadow->color();
     
    337339}
    338340
    339 static void paintTextWithShadows(GraphicsContext* context, const Font& font, const TextRun& textRun, int startOffset, int endOffset, int truncationPoint, const IntPoint& textOrigin, int x, int y, int w, int h, const ShadowData* shadow, bool stroked)
     341static void paintTextWithShadows(GraphicsContext* context, const Font& font, const TextRun& textRun, int startOffset, int endOffset, int truncationPoint, const IntPoint& textOrigin,
     342                                 int x, int y, int w, int h, const ShadowData* shadow, bool stroked, bool vertical)
    340343{
    341344    Color fillColor = context->fillColor();
     
    348351        IntSize extraOffset;
    349352        if (shadow)
    350             extraOffset = roundedIntSize(InlineTextBox::applyShadowToGraphicsContext(context, shadow, FloatRect(x, y, w, h), stroked, opaque));
     353            extraOffset = roundedIntSize(InlineTextBox::applyShadowToGraphicsContext(context, shadow, FloatRect(x, y, w, h), stroked, opaque, vertical));
    351354        else if (!opaque)
    352355            context->setFillColor(fillColor, fillColorSpace);
     
    376379{
    377380    if (isLineBreak() || !paintInfo.shouldPaintWithinRoot(renderer()) || renderer()->style()->visibility() != VISIBLE ||
    378         m_truncation == cFullTruncation || paintInfo.phase == PaintPhaseOutline)
     381        m_truncation == cFullTruncation || paintInfo.phase == PaintPhaseOutline || !m_len)
    379382        return;
    380383
     
    411414            int widthOfHiddenText = m_logicalWidth - widthOfVisibleText;
    412415            // FIXME: The hit testing logic also needs to take this translation int account.
    413             tx += isLeftToRightDirection() ? widthOfHiddenText : -widthOfHiddenText;
     416            if (!m_isVertical)
     417                tx += isLeftToRightDirection() ? widthOfHiddenText : -widthOfHiddenText;
     418            else
     419                ty += isLeftToRightDirection() ? widthOfHiddenText : -widthOfHiddenText;
    414420        }
    415421    }
     
    417423    GraphicsContext* context = paintInfo.context;
    418424
     425    RenderStyle* styleToUse = renderer()->style(m_firstLine);
     426    int baseline = styleToUse->font().ascent();
     427    ty -= styleToUse->isFlippedLinesWritingMode() ? baseline : 0;
     428    IntPoint textOrigin(m_x + tx, m_y + ty + baseline);
     429   
     430    if (m_isVertical) {
     431        context->save();
     432        context->translate(textOrigin.x(), textOrigin.y());
     433        context->rotate(deg2rad(90.));
     434        context->translate(-textOrigin.x(), -textOrigin.y());
     435    }
     436   
    419437    // Determine whether or not we have composition underlines to draw.
    420438    bool containsComposition = renderer()->node() && renderer()->frame()->editor()->compositionNode() == renderer()->node();
     
    422440
    423441    // Set our font.
    424     RenderStyle* styleToUse = renderer()->style(m_firstLine);
    425442    int d = styleToUse->textDecorationsInEffect();
    426443    const Font& font = styleToUse->font();
     
    447464
    448465    // 2. Now paint the foreground, including text and decorations like underline/overline (in quirks mode only).
    449     if (m_len <= 0)
    450         return;
    451 
    452466    Color textFillColor;
    453467    Color textStrokeColor;
     
    518532        adjustCharactersAndLengthForHyphen(charactersWithHyphen, styleToUse, characters, length);
    519533
    520     int baseline = renderer()->style(m_firstLine)->font().ascent();
    521     IntPoint textOrigin(m_x + tx, m_y + ty + baseline);
    522534    TextRun textRun(characters, length, textRenderer()->allowTabs(), textPos(), m_toAdd, !isLeftToRightDirection(), m_dirOverride || styleToUse->visuallyOrdered());
    523535
     
    542554        if (!paintSelectedTextSeparately || ePos <= sPos) {
    543555            // FIXME: Truncate right-to-left text correctly.
    544             paintTextWithShadows(context, font, textRun, 0, length, length, textOrigin, m_x + tx, m_y + ty, logicalWidth(), logicalHeight(), textShadow, textStrokeWidth > 0);
     556            paintTextWithShadows(context, font, textRun, 0, length, length, textOrigin, m_x + tx, m_y + ty, logicalWidth(), logicalHeight(), textShadow, textStrokeWidth > 0, m_isVertical);
    545557        } else
    546             paintTextWithShadows(context, font, textRun, ePos, sPos, length, textOrigin, m_x + tx, m_y + ty, logicalWidth(), logicalHeight(), textShadow, textStrokeWidth > 0);
     558            paintTextWithShadows(context, font, textRun, ePos, sPos, length, textOrigin, m_x + tx, m_y + ty, logicalWidth(), logicalHeight(), textShadow, textStrokeWidth > 0, m_isVertical);
    547559
    548560        if (textStrokeWidth > 0)
     
    556568
    557569        updateGraphicsContext(context, selectionFillColor, selectionStrokeColor, selectionStrokeWidth, styleToUse->colorSpace());
    558         paintTextWithShadows(context, font, textRun, sPos, ePos, length, textOrigin, m_x + tx, m_y + ty, logicalWidth(), logicalHeight(), selectionShadow, selectionStrokeWidth > 0);
     570        paintTextWithShadows(context, font, textRun, sPos, ePos, length, textOrigin, m_x + tx, m_y + ty, logicalWidth(), logicalHeight(), selectionShadow, selectionStrokeWidth > 0, m_isVertical);
    559571
    560572        if (selectionStrokeWidth > 0)
     
    563575
    564576    // Paint decorations
    565     if (d != TDNONE && paintInfo.phase != PaintPhaseSelection && renderer()->document()->inQuirksMode()) {
    566         context->setStrokeColor(styleToUse->visitedDependentColor(CSSPropertyColor), styleToUse->colorSpace());
     577    if (d != TDNONE && paintInfo.phase != PaintPhaseSelection) {
     578        updateGraphicsContext(context, textFillColor, textStrokeColor, textStrokeWidth, styleToUse->colorSpace());
    567579        paintDecoration(context, tx, ty, d, textShadow);
    568580    }
     
    596608        }
    597609    }
     610   
     611    if (m_isVertical)
     612        context->restore();
    598613}
    599614
     
    724739    bool linesAreOpaque = !isPrinting && (!(deco & UNDERLINE) || underline.alpha() == 255) && (!(deco & OVERLINE) || overline.alpha() == 255) && (!(deco & LINE_THROUGH) || linethrough.alpha() == 255);
    725740
    726     int baseline = renderer()->style(m_firstLine)->font().ascent();
     741    RenderStyle* styleToUse = renderer()->style(m_firstLine);
     742    int baseline = styleToUse->font().ascent();
    727743
    728744    bool setClip = false;
     
    734750            IntRect shadowRect(tx, ty, width, baseline + 2);
    735751            shadowRect.inflate(s->blur());
    736             shadowRect.move(s->x(), s->y());
     752            int shadowX = m_isVertical ? s->y() : s->x();
     753            int shadowY = m_isVertical ? -s->x() : s->y();
     754            shadowRect.move(shadowX, shadowY);
    737755            clipRect.unite(shadowRect);
    738             extraOffset = max(extraOffset, max(0, s->y()) + s->blur());
     756            extraOffset = max(extraOffset, max(0, shadowY) + s->blur());
    739757        }
    740758        context->save();
     
    755773                extraOffset = 0;
    756774            }
    757             context->setShadow(IntSize(shadow->x(), shadow->y() - extraOffset), shadow->blur(), shadow->color(), colorSpace);
     775            int shadowX = m_isVertical ? shadow->y() : shadow->x();
     776            int shadowY = m_isVertical ? -shadow->x() : shadow->y();
     777            context->setShadow(IntSize(shadowX, shadowY - extraOffset), shadow->blur(), shadow->color(), colorSpace);
    758778            setShadow = true;
    759779            shadow = shadow->next();
     
    880900    markerRect = renderer()->localToAbsoluteQuad(FloatRect(markerRect)).enclosingBoundingBox();
    881901    renderer()->document()->markers()->setRenderedRectForMarker(renderer()->node(), marker, markerRect);
    882      
     902   
    883903    // Optionally highlight the text
    884904    if (renderer()->frame()->editor()->markedTextMatchesAreHighlighted()) {
  • trunk/WebCore/rendering/InlineTextBox.h

    r70072 r70263  
    128128
    129129    // Needs to be public, so the static paintTextWithShadows() function can use it.
    130     static FloatSize applyShadowToGraphicsContext(GraphicsContext*, const ShadowData*, const FloatRect& textRect, bool stroked, bool opaque);
     130    static FloatSize applyShadowToGraphicsContext(GraphicsContext*, const ShadowData*, const FloatRect& textRect, bool stroked, bool opaque, bool vertical);
    131131
    132132private:
  • trunk/WebCore/rendering/svg/SVGInlineTextBox.cpp

    r70072 r70263  
    524524        FloatSize extraOffset;
    525525        if (shadow)
    526             extraOffset = applyShadowToGraphicsContext(context, shadow, shadowRect, false /* stroked */, true /* opaque */);
     526            extraOffset = applyShadowToGraphicsContext(context, shadow, shadowRect, false /* stroked */, true /* opaque */, false /* vertical */);
    527527
    528528        font.drawText(context, textRun, textOrigin + extraOffset, startPosition, endPosition);
Note: See TracChangeset for help on using the changeset viewer.