Changeset 158467 in webkit
- Timestamp:
- Nov 1, 2013 4:46:54 PM (10 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r158466 r158467 1 2013-11-01 Myles C. Maxfield <mmaxfield@apple.com> 2 3 Initial implementation of text-decoration-skip ink 4 https://bugs.webkit.org/show_bug.cgi?id=121806 5 6 Reviewed by Darin Adler. 7 8 Adding a test which draws a very large "p" with text-decoration-skip:ink. The 9 viewport is restricted to be just hugging the place where an underline would 10 intersect the descender of the "p". This should look the same as if there was 11 no underline at all (because of the skipping underline). 12 13 * fast/css3-text/css3-text-decoration/text-decoration-skip/text-decoration-skip-ink-expected.html: Added. 14 * fast/css3-text/css3-text-decoration/text-decoration-skip/text-decoration-skip-ink.html: Added. 15 1 16 2013-11-01 Hans Muller <hmuller@adobe.com> 2 17 -
trunk/Source/WebCore/ChangeLog
r158465 r158467 1 2013-11-01 Myles C. Maxfield <mmaxfield@apple.com> 2 3 Initial implementation of text-decoration-skip ink 4 https://bugs.webkit.org/show_bug.cgi?id=121806 5 6 Reviewed by Darin Adler. 7 8 text-decoration-skip: ink is implemented by the following steps: 9 1. Before drawing any decorations, figure out the bounding box for the decorations that will be drawn 10 2. Create an ImageBuffer with these dimensions 11 3. Draw text into this ImageBuffer with a thicker stroke 12 4. Apply the ImageBuffer as a mask to the context 13 5. Draw decorations like normal 14 6. Clean up 15 16 Test: fast/css3-text/css3-text-decoration/text-decoration-skip/text-decoration-skip-ink.html 17 18 * platform/graphics/cg/GraphicsContextCG.cpp: 19 (WebCore::computeLineBoundsAndAntialiasingModeForText): Don't call GraphicsContext::roundToDevicePixels 20 when painting is disabled 21 * rendering/InlineTextBox.cpp: 22 (WebCore::InlineTextBox::paint): Pass the TextPainter to paintDecoration 23 (WebCore::computeUnderlineOffset): Small cleanup 24 (WebCore::getWavyStrokeControlPointDistance): Pulling out of strokeWavyTextDecoration() 25 (WebCore::getWavyStrokeStep): Ditto 26 (WebCore::strokeWavyTextDecoration): Use the previous 2 functions 27 (WebCore::getSingleDecorationBoundingBox): Pulling out repeated code into a function 28 (WebCore::getDecorationBoundingBox): Compute the bounding box for an underline which 29 hasn't been drawn yet 30 (WebCore::InlineTextBox::paintDecoration): Construct a mask and apply it to the GraphicsContext 31 * rendering/InlineTextBox.h: paintDecoration needs the TextPainter 32 * rendering/style/RenderStyle.cpp: 33 (WebCore::RenderStyle::changeRequiresRepaintIfTextOrBorderOrOutline): Redraw the underline when 34 text-decoration-skip changes 35 1 36 2013-11-01 Andreas Kling <akling@apple.com> 2 37 -
trunk/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
r158392 r158467 1247 1247 FloatRect initialBounds(point, FloatSize(width, max(context.strokeThickness(), 0.5f))); 1248 1248 1249 if (printing || !context.getCTM(GraphicsContext::DefinitelyIncludeDeviceScale).preservesAxisAlignment())1249 if (printing || context.paintingDisabled() || !context.getCTM(GraphicsContext::DefinitelyIncludeDeviceScale).preservesAxisAlignment()) 1250 1250 return initialBounds; 1251 1251 -
trunk/Source/WebCore/rendering/InlineTextBox.cpp
r158461 r158467 34 34 #include "GraphicsContext.h" 35 35 #include "HitTestResult.h" 36 #include "ImageBuffer.h" 36 37 #include "Page.h" 37 38 #include "PaintInfo.h" … … 581 582 if (combinedText) 582 583 context->concatCTM(rotation(boxRect, Clockwise)); 583 paintDecoration( context, boxOrigin, textDecorations, lineStyle.textDecorationStyle(), textShadow);584 paintDecoration(*context, boxOrigin, textDecorations, lineStyle.textDecorationStyle(), textShadow, textPainter); 584 585 if (combinedText) 585 586 context->concatCTM(rotation(boxRect, Counterclockwise)); … … 779 780 // Position underline relative to the under edge of the lowest element's content box. 780 781 const float offset = inlineTextBox->root().maxLogicalTop() - inlineTextBox->logicalTop(); 781 if (offset > 0) 782 return inlineTextBox->logicalHeight() + gap + offset; 783 return inlineTextBox->logicalHeight() + gap; 782 return inlineTextBox->logicalHeight() + gap + std::max<float>(offset, 0); 784 783 } 785 784 } … … 805 804 step += adjustment; 806 805 controlPointDistance += adjustment; 806 } 807 808 static void getWavyStrokeParameters(float strokeThickness, float& controlPointDistance, float& step) 809 { 810 // Distance between decoration's axis and Bezier curve's control points. 811 // The height of the curve is based on this distance. Use a minimum of 6 pixels distance since 812 // the actual curve passes approximately at half of that distance, that is 3 pixels. 813 // The minimum height of the curve is also approximately 3 pixels. Increases the curve's height 814 // as strockThickness increases to make the curve looks better. 815 controlPointDistance = 3 * std::max<float>(2, strokeThickness); 816 817 // Increment used to form the diamond shape between start point (p1), control 818 // points and end point (p2) along the axis of the decoration. Makes the 819 // curve wider as strockThickness increases to make the curve looks better. 820 step = 2 * std::max<float>(2, strokeThickness); 807 821 } 808 822 … … 834 848 * step 835 849 */ 836 static void strokeWavyTextDecoration(GraphicsContext *context, FloatPoint& p1, FloatPoint& p2, float strokeThickness)837 { 838 context ->adjustLineToPixelBoundaries(p1, p2, strokeThickness, context->strokeStyle());850 static void strokeWavyTextDecoration(GraphicsContext& context, FloatPoint& p1, FloatPoint& p2, float strokeThickness) 851 { 852 context.adjustLineToPixelBoundaries(p1, p2, strokeThickness, context.strokeStyle()); 839 853 840 854 Path path; 841 855 path.moveTo(p1); 842 856 843 // Distance between decoration's axis and Bezier curve's control points. 844 // The height of the curve is based on this distance. Use a minimum of 6 pixels distance since 845 // the actual curve passes approximately at half of that distance, that is 3 pixels. 846 // The minimum height of the curve is also approximately 3 pixels. Increases the curve's height 847 // as strockThickness increases to make the curve looks better. 848 float controlPointDistance = 3 * max<float>(2, strokeThickness); 849 850 // Increment used to form the diamond shape between start point (p1), control 851 // points and end point (p2) along the axis of the decoration. Makes the 852 // curve wider as strockThickness increases to make the curve looks better. 853 float step = 2 * max<float>(2, strokeThickness); 857 float controlPointDistance; 858 float step; 859 getWavyStrokeParameters(strokeThickness, controlPointDistance, step); 854 860 855 861 bool isVerticalLine = (p1.x() == p2.x()); … … 907 913 } 908 914 909 context->setShouldAntialias(true); 910 context->strokePath(path); 915 context.setShouldAntialias(true); 916 context.strokePath(path); 917 } 918 919 // Because finding the bounding box of an underline is structurally similar to finding 920 // the bounding box of a strikethrough, we can pull out the computation and parameterize 921 // by the location of the decoration (yOffset, underlineOffset, and doubleOffset). 922 static FloatRect boundingBoxForSingleDecoration(GraphicsContext& context, float textDecorationThickness, 923 float width, FloatPoint localOrigin, TextDecorationStyle decorationStyle, 924 bool isPrinting, float yOffset, float underlineOffset, float doubleOffset) 925 { 926 FloatRect boundingBox; 927 928 switch (decorationStyle) { 929 case TextDecorationStyleWavy: { 930 FloatPoint start(localOrigin.x(), localOrigin.y() + yOffset); 931 FloatPoint end = start + FloatSize(width, 0); 932 context.adjustLineToPixelBoundaries(start, end, textDecorationThickness, context.strokeStyle()); 933 934 float controlPointDistance; 935 float step; 936 getWavyStrokeParameters(textDecorationThickness, controlPointDistance, step); 937 938 adjustStepToDecorationLength(step, controlPointDistance, width); 939 940 controlPointDistance += textDecorationThickness; 941 FloatPoint boundingBoxOrigin = start - FloatSize(0, controlPointDistance); 942 FloatSize boundingBoxSize = FloatSize(width, 2 * controlPointDistance); 943 boundingBox = FloatRect(boundingBoxOrigin, boundingBoxSize); 944 break; 945 } 946 default: 947 boundingBox = context.computeLineBoundsForText(localOrigin + FloatSize(0, underlineOffset), width, isPrinting); 948 if (decorationStyle == TextDecorationStyleDouble) 949 boundingBox.unite(context.computeLineBoundsForText(localOrigin + FloatSize(0, doubleOffset), width, isPrinting)); 950 } 951 return boundingBox; 952 } 953 954 static FloatRect boundingBoxForAllActiveDecorations(InlineTextBox& inlineTextBox, GraphicsContext& context, TextDecoration decoration, float textDecorationThickness, float width, float doubleOffset, TextDecorationStyle decorationStyle, const FloatPoint localOrigin, const RenderStyle& lineStyle, bool isPrinting, int baseline) 955 { 956 FloatRect boundingBox; 957 if (decoration & TextDecorationUnderline) { 958 int underlineOffset = computeUnderlineOffset(lineStyle.textUnderlinePosition(), lineStyle.fontMetrics(), &inlineTextBox, textDecorationThickness); 959 960 boundingBox.unite(boundingBoxForSingleDecoration(context, textDecorationThickness, width, localOrigin, decorationStyle, isPrinting, underlineOffset + doubleOffset, underlineOffset, baseline + 1)); 961 } 962 if (decoration & TextDecorationOverline) 963 boundingBox.unite(boundingBoxForSingleDecoration(context, textDecorationThickness, width, localOrigin, decorationStyle, isPrinting, -doubleOffset, 0, -doubleOffset)); 964 if (decoration & TextDecorationLineThrough) 965 boundingBox.unite(boundingBoxForSingleDecoration(context, textDecorationThickness, width, localOrigin, decorationStyle, isPrinting, 2 * baseline / 3, 2 * baseline / 3, doubleOffset + 2 * baseline / 3)); 966 return boundingBox; 911 967 } 912 968 #endif // CSS3_TEXT_DECORATION 913 969 914 void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& boxOrigin, TextDecoration deco, TextDecorationStyle decorationStyle, const ShadowData* shadow) 915 { 970 void InlineTextBox::paintDecoration(GraphicsContext& context, const FloatPoint& boxOrigin, TextDecoration decoration, TextDecorationStyle decorationStyle, const ShadowData* shadow, TextPainter& textPainter) 971 { 972 #if !ENABLE(CSS3_TEXT_DECORATION) 973 UNUSED_PARAM(textPainter); 974 #endif 916 975 // FIXME: We should improve this rule and not always just assume 1. 917 976 const float textDecorationThickness = 1.f; … … 931 990 // Get the text decoration colors. 932 991 Color underline, overline, linethrough; 933 renderer().getTextDecorationColors(deco , underline, overline, linethrough, true);992 renderer().getTextDecorationColors(decoration, underline, overline, linethrough, true); 934 993 if (isFirstLine()) 935 renderer().getTextDecorationColors(deco , underline, overline, linethrough, true, true);994 renderer().getTextDecorationColors(decoration, underline, overline, linethrough, true, true); 936 995 937 996 // Use a special function for underlines to get the positioning exactly right. 938 997 bool isPrinting = renderer().document().printing(); 939 context ->setStrokeThickness(textDecorationThickness);940 941 bool linesAreOpaque = !isPrinting && (!(deco & TextDecorationUnderline) || underline.alpha() == 255) && (!(deco & TextDecorationOverline) || overline.alpha() == 255) && (!(deco& TextDecorationLineThrough) || linethrough.alpha() == 255);998 context.setStrokeThickness(textDecorationThickness); 999 1000 bool linesAreOpaque = !isPrinting && (!(decoration & TextDecorationUnderline) || underline.alpha() == 255) && (!(decoration & TextDecorationOverline) || overline.alpha() == 255) && (!(decoration & TextDecorationLineThrough) || linethrough.alpha() == 255); 942 1001 943 1002 const RenderStyle& lineStyle = this->lineStyle(); … … 958 1017 extraOffset = max(extraOffset, max(0, shadowY) + shadowExtent); 959 1018 } 960 context ->save();961 context ->clip(clipRect);1019 context.save(); 1020 context.clip(clipRect); 962 1021 extraOffset += baseline + 2; 963 1022 localOrigin.move(0, extraOffset); … … 977 1036 int shadowX = isHorizontal() ? shadow->x() : shadow->y(); 978 1037 int shadowY = isHorizontal() ? shadow->y() : -shadow->x(); 979 context ->setShadow(FloatSize(shadowX, shadowY - extraOffset), shadow->radius(), shadow->color(), colorSpace);1038 context.setShadow(FloatSize(shadowX, shadowY - extraOffset), shadow->radius(), shadow->color(), colorSpace); 980 1039 setShadow = true; 981 1040 shadow = shadow->next(); … … 984 1043 #if ENABLE(CSS3_TEXT_DECORATION) 985 1044 // Offset between lines - always non-zero, so lines never cross each other. 986 float doubleOffset = textDecorationThickness + 1.f; 1045 float doubleOffset = textDecorationThickness + 1; 1046 1047 bool clipDecorationToMask = lineStyle.textDecorationSkip() == TextDecorationSkipInk; 1048 1049 GraphicsContextStateSaver stateSaver(context, false); 1050 1051 if (clipDecorationToMask) { 1052 const float skipInkGapWidth = 1; 1053 1054 stateSaver.save(); 1055 1056 FloatRect underlineRect = boundingBoxForAllActiveDecorations(*this, context, decoration, textDecorationThickness, width, doubleOffset, decorationStyle, localOrigin, lineStyle, isPrinting, baseline); 1057 IntRect enclosingDeviceRect = enclosingIntRect(underlineRect); 1058 OwnPtr<ImageBuffer> imageBuffer = context.createCompatibleBuffer(enclosingDeviceRect.size()); 1059 1060 if (imageBuffer.get()) { 1061 GraphicsContext& maskContext = *imageBuffer->context(); 1062 maskContext.setFillColor(Color::black, ColorSpaceDeviceRGB); 1063 maskContext.setLineJoin(RoundJoin); 1064 maskContext.translate(FloatPoint() - enclosingDeviceRect.location()); 1065 1066 maskContext.fillRect(enclosingDeviceRect); 1067 maskContext.setCompositeOperation(CompositeClear); 1068 1069 textPainter.paintTextInContext(maskContext, skipInkGapWidth); 1070 1071 context.clipToImageBuffer(imageBuffer.get(), enclosingDeviceRect); 1072 } 1073 } 987 1074 #endif // CSS3_TEXT_DECORATION 988 context ->setStrokeStyle(textDecorationStyleToStrokeStyle(decorationStyle));989 if (deco & TextDecorationUnderline) {990 context ->setStrokeColor(underline, colorSpace);1075 context.setStrokeStyle(textDecorationStyleToStrokeStyle(decorationStyle)); 1076 if (decoration & TextDecorationUnderline) { 1077 context.setStrokeColor(underline, colorSpace); 991 1078 #if ENABLE(CSS3_TEXT_DECORATION) 992 1079 TextUnderlinePosition underlinePosition = lineStyle.textUnderlinePosition(); … … 1001 1088 } 1002 1089 default: 1003 context ->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + underlineOffset), width, isPrinting);1090 context.drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + underlineOffset), width, isPrinting); 1004 1091 1005 1092 if (decorationStyle == TextDecorationStyleDouble) 1006 context ->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + underlineOffset + doubleOffset), width, isPrinting);1093 context.drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + underlineOffset + doubleOffset), width, isPrinting); 1007 1094 } 1008 1095 #else 1009 1096 // Leave one pixel of white between the baseline and the underline. 1010 context ->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + baseline + 1), width, isPrinting);1097 context.drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + baseline + 1), width, isPrinting); 1011 1098 #endif // CSS3_TEXT_DECORATION 1012 1099 } 1013 if (deco & TextDecorationOverline) {1014 context ->setStrokeColor(overline, colorSpace);1100 if (decoration & TextDecorationOverline) { 1101 context.setStrokeColor(overline, colorSpace); 1015 1102 #if ENABLE(CSS3_TEXT_DECORATION) 1016 1103 switch (decorationStyle) { … … 1023 1110 default: 1024 1111 #endif // CSS3_TEXT_DECORATION 1025 context ->drawLineForText(localOrigin, width, isPrinting);1112 context.drawLineForText(localOrigin, width, isPrinting); 1026 1113 #if ENABLE(CSS3_TEXT_DECORATION) 1027 1114 if (decorationStyle == TextDecorationStyleDouble) 1028 context ->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() - doubleOffset), width, isPrinting);1115 context.drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() - doubleOffset), width, isPrinting); 1029 1116 } 1030 1117 #endif // CSS3_TEXT_DECORATION 1031 1118 } 1032 if (deco & TextDecorationLineThrough) { 1033 context->setStrokeColor(linethrough, colorSpace); 1119 #if ENABLE(CSS3_TEXT_DECORATION) 1120 if (clipDecorationToMask) 1121 stateSaver.restore(); 1122 #endif 1123 if (decoration & TextDecorationLineThrough) { 1124 context.setStrokeColor(linethrough, colorSpace); 1034 1125 #if ENABLE(CSS3_TEXT_DECORATION) 1035 1126 switch (decorationStyle) { … … 1042 1133 default: 1043 1134 #endif // CSS3_TEXT_DECORATION 1044 context ->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + 2 * baseline / 3), width, isPrinting);1135 context.drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + 2 * baseline / 3), width, isPrinting); 1045 1136 #if ENABLE(CSS3_TEXT_DECORATION) 1046 1137 if (decorationStyle == TextDecorationStyleDouble) 1047 context ->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + doubleOffset + 2 * baseline / 3), width, isPrinting);1138 context.drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + doubleOffset + 2 * baseline / 3), width, isPrinting); 1048 1139 } 1049 1140 #endif // CSS3_TEXT_DECORATION … … 1052 1143 1053 1144 if (setClip) 1054 context ->restore();1145 context.restore(); 1055 1146 else if (setShadow) 1056 context ->clearShadow();1147 context.clearShadow(); 1057 1148 } 1058 1149 -
trunk/Source/WebCore/rendering/InlineTextBox.h
r158343 r158467 33 33 struct CompositionUnderline; 34 34 class DocumentMarker; 35 class TextPainter; 35 36 36 37 const unsigned short cNoTruncation = USHRT_MAX; … … 170 171 171 172 private: 172 void paintDecoration(GraphicsContext *, const FloatPoint& boxOrigin, TextDecoration, TextDecorationStyle, const ShadowData*);173 void paintDecoration(GraphicsContext&, const FloatPoint& boxOrigin, TextDecoration, TextDecorationStyle, const ShadowData*, TextPainter&); 173 174 void paintSelection(GraphicsContext*, const FloatPoint& boxOrigin, const RenderStyle&, const Font&, Color textColor); 174 175 void paintDocumentMarker(GraphicsContext*, const FloatPoint& boxOrigin, DocumentMarker*, const RenderStyle&, const Font&, bool grammar); -
trunk/Source/WebCore/rendering/style/RenderStyle.cpp
r158461 r158467 792 792 || rareNonInheritedData->m_textDecorationStyle != other->rareNonInheritedData->m_textDecorationStyle 793 793 || rareNonInheritedData->m_textDecorationColor != other->rareNonInheritedData->m_textDecorationColor 794 || rareInheritedData->m_textDecorationSkip != other->rareInheritedData->m_textDecorationSkip 794 795 #endif // CSS3_TEXT_DECORATION 795 796 || rareInheritedData->textFillColor != other->rareInheritedData->textFillColor
Note: See TracChangeset
for help on using the changeset viewer.