https://bugs.webkit.org/show_bug.cgi?id=138762
Patch by Myles C. Maxfield <litherum@gmail.com> on 2014-11-18
Reviewed by Dave Hyatt.
Source/WebCore:
Test: platform/mac/fast/css3-text/css3-text-decoration/text-decoration-thickness.html
* platform/graphics/FontMetrics.h: Adding variables for text decoration thickness and
underline position.
(WebCore::FontMetrics::FontMetrics):
(WebCore::FontMetrics::decorationThickness):
(WebCore::FontMetrics::setDecorationThickness):
(WebCore::FontMetrics::underlinePosition):
(WebCore::FontMetrics::setUnderlinePosition):
* platform/graphics/freetype/SimpleFontDataFreeType.cpp:
(WebCore::SimpleFontData::platformInit): Initialize new FontMetrics members.
* platform/graphics/ios/SimpleFontDataIOS.mm:
(WebCore::SimpleFontData::platformInit): Ditto.
* platform/graphics/mac/SimpleFontDataMac.mm:
(WebCore::SimpleFontData::platformInit): Ditto.
* platform/graphics/win/SimpleFontDataCGWin.cpp:
(WebCore::SimpleFontData::platformInit): Ditto.
* platform/graphics/win/SimpleFontDataCairoWin.cpp:
(WebCore::SimpleFontData::platformInit): Ditto.
* platform/graphics/win/SimpleFontDataWin.cpp:
(WebCore::SimpleFontData::initGDIFont): Ditto.
* rendering/InlineTextBox.cpp:
(WebCore::InlineTextBox::paintDecoration): Use FontMetrics data.
* style/InlineTextBoxStyle.cpp:
(WebCore::computeUnderlineOffset): Ditto.
(WebCore::visualOverflowForDecorations): Ditto.
* style/InlineTextBoxStyle.h:
(WebCore::textDecorationStrokeThickness): Deleted.
* svg/SVGFontData.cpp:
(WebCore::SVGFontData::initializeFontData): Initialize new FontMetrics members.
LayoutTests:
This patch makes underline placement platform-dependent.
* platform/mac/fast/css3-text/css3-text-decoration/text-decoration-thickness-expected.html: Renamed from LayoutTests/fast/css3-text/css3-text-decoration/text-decoration-thickness-expected.html.
* platform/mac/fast/css3-text/css3-text-decoration/text-decoration-thickness.html: Renamed from LayoutTests/fast/css3-text/css3-text-decoration/text-decoration-thickness.html.
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@176263
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2014-11-18 Myles C. Maxfield <litherum@gmail.com>
+
+ Use underlining metrics from the font file
+ https://bugs.webkit.org/show_bug.cgi?id=138762
+
+ Reviewed by Dave Hyatt.
+
+ This patch makes underline placement platform-dependent.
+
+ * platform/mac/fast/css3-text/css3-text-decoration/text-decoration-thickness-expected.html: Renamed from LayoutTests/fast/css3-text/css3-text-decoration/text-decoration-thickness-expected.html.
+ * platform/mac/fast/css3-text/css3-text-decoration/text-decoration-thickness.html: Renamed from LayoutTests/fast/css3-text/css3-text-decoration/text-decoration-thickness.html.
+
2014-11-17 David Hyatt <hyatt@apple.com>
Improve Ruby selection (getting rid of overlap and improving gap filling)
the text so that the underline should fill a box if the underline grows in proportion
to text size. The comparison is to a box that has its background color set.
<div style="position: relative; width: 600px; height: 600px; overflow: hidden;">
-<div style="font-family: Ahem; text-decoration: underline; font-size: 10000px; position: absolute; left: 0px; top: -8350px;"> </div>
+<div style="font-family: Ahem; text-decoration: underline; font-size: 31000px; position: absolute; left: 0px; top: -28925px;"> </div>
</div>
</body>
</html>
+2014-11-18 Myles C. Maxfield <litherum@gmail.com>
+
+ Use underlining metrics from the font file
+ https://bugs.webkit.org/show_bug.cgi?id=138762
+
+ Reviewed by Dave Hyatt.
+
+ Test: platform/mac/fast/css3-text/css3-text-decoration/text-decoration-thickness.html
+
+ * platform/graphics/FontMetrics.h: Adding variables for text decoration thickness and
+ underline position.
+ (WebCore::FontMetrics::FontMetrics):
+ (WebCore::FontMetrics::decorationThickness):
+ (WebCore::FontMetrics::setDecorationThickness):
+ (WebCore::FontMetrics::underlinePosition):
+ (WebCore::FontMetrics::setUnderlinePosition):
+ * platform/graphics/freetype/SimpleFontDataFreeType.cpp:
+ (WebCore::SimpleFontData::platformInit): Initialize new FontMetrics members.
+ * platform/graphics/ios/SimpleFontDataIOS.mm:
+ (WebCore::SimpleFontData::platformInit): Ditto.
+ * platform/graphics/mac/SimpleFontDataMac.mm:
+ (WebCore::SimpleFontData::platformInit): Ditto.
+ * platform/graphics/win/SimpleFontDataCGWin.cpp:
+ (WebCore::SimpleFontData::platformInit): Ditto.
+ * platform/graphics/win/SimpleFontDataCairoWin.cpp:
+ (WebCore::SimpleFontData::platformInit): Ditto.
+ * platform/graphics/win/SimpleFontDataWin.cpp:
+ (WebCore::SimpleFontData::initGDIFont): Ditto.
+ * rendering/InlineTextBox.cpp:
+ (WebCore::InlineTextBox::paintDecoration): Use FontMetrics data.
+ * style/InlineTextBoxStyle.cpp:
+ (WebCore::computeUnderlineOffset): Ditto.
+ (WebCore::visualOverflowForDecorations): Ditto.
+ * style/InlineTextBoxStyle.h:
+ (WebCore::textDecorationStrokeThickness): Deleted.
+ * svg/SVGFontData.cpp:
+ (WebCore::SVGFontData::initializeFontData): Initialize new FontMetrics members.
+
2014-11-17 David Hyatt <hyatt@apple.com>
Improve Ruby selection (getting rid of overlap and improving gap filling)
, m_lineSpacing(0)
, m_xHeight(0)
, m_zeroWidth(0)
+ , m_decorationThickness(1)
+ , m_underlinePosition(1)
, m_hasXHeight(false)
, m_hasZeroWidth(false)
{
bool hasZeroWidth() const { return m_hasZeroWidth; }
void setHasZeroWidth(bool hasZeroWidth) { m_hasZeroWidth = hasZeroWidth; }
+ float decorationThickness() const { return m_decorationThickness; }
+ void setDecorationThickness(float decorationThickness) { m_decorationThickness = decorationThickness; }
+
+ float underlinePosition() const { return m_underlinePosition; }
+ void setUnderlinePosition(float underlinePosition) { m_underlinePosition = underlinePosition; }
+
private:
friend class SimpleFontData;
float m_xHeight;
float m_capHeight;
float m_zeroWidth;
+ float m_decorationThickness;
+ float m_underlinePosition;
bool m_hasXHeight;
bool m_hasCapHeight;
bool m_hasZeroWidth;
return width;
}
+static inline void populateDecorationMetrics(float fontSize, float& decorationThickness, float& underlinePosition)
+{
+ // Decoration underlines should be proportional to the font size
+ decorationThickness = fontSize / 16.0f;
+ // An amount to lower the underline below the baseline
+ underlinePosition = std::max(1.0f, ceilf(decorationThickness / 2.0));
+}
+
} // namespace WebCore
SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::SimpleFontData)
float descent = narrowPrecisionToFloat(fontExtents.descent);
float capHeight = narrowPrecisionToFloat(fontExtents.height);
float lineGap = narrowPrecisionToFloat(fontExtents.height - fontExtents.ascent - fontExtents.descent);
+ float decorationThickness;
+ float underlinePosition;
+ populateDecorationMetrics(m_platformData.m_size, decorationThickness, underlinePosition);
m_fontMetrics.setAscent(ascent);
m_fontMetrics.setDescent(descent);
m_fontMetrics.setCapHeight(capHeight);
+ m_fontMetrics.setDecorationThickness(decorationThickness);
+ m_fontMetrics.setUnderlinePosition(underlinePosition);
#if PLATFORM(EFL)
m_fontMetrics.setLineSpacing(ascent + descent + lineGap);
float lineGap;
float lineSpacing;
float xHeight;
+ float decorationThickness;
+ float underlinePosition;
RetainPtr<CFStringRef> familyName;
if (CTFontRef ctFont = m_platformData.font()) {
FontServicesIOS fontService(ctFont);
lineSpacing = fontService.lineSpacing();
lineGap = fontService.lineGap();
xHeight = fontService.xHeight();
+ decorationThickness = CTFontGetUnderlineThickness(ctFont);
+ underlinePosition = -CTFontGetUnderlinePosition(ctFont);
capHeight = fontService.capHeight();
unitsPerEm = fontService.unitsPerEm();
familyName = adoptCF(CTFontCopyFamilyName(ctFont));
lineGap = lroundf(scaleEmToUnits(CGFontGetLeading(cgFont), unitsPerEm) * pointSize);
xHeight = scaleEmToUnits(CGFontGetXHeight(cgFont), unitsPerEm) * pointSize;
capHeight = scaleEmToUnits(CGFontGetCapHeight(cgFont), unitsPerEm) * pointSize;
+ float decorationThickness;
+ float underlinePosition;
+ populateDecorationMetrics(m_platformData.size(), decorationThickness, underlinePosition);
lineSpacing = ascent + descent + lineGap;
familyName = adoptCF(CGFontCopyFamilyName(cgFont));
m_fontMetrics.setLineSpacing(lineSpacing);
m_fontMetrics.setXHeight(xHeight);
m_fontMetrics.setCapHeight(capHeight);
+ m_fontMetrics.setDecorationThickness(decorationThickness);
+ m_fontMetrics.setUnderlinePosition(underlinePosition);
m_shouldNotBeUsedForArabic = fontFamilyShouldNotBeUsedForArabic(familyName.get());
if (platformData().orientation() == Vertical && !isTextOrientationFallback())
float capHeight = scaleEmToUnits(iCapHeight, unitsPerEm) * pointSize;
float lineGap = scaleEmToUnits(iLineGap, unitsPerEm) * pointSize;
+ float decorationThickness = CTFontGetUnderlineThickness(m_platformData.ctFont());
+ float underlinePosition = -CTFontGetUnderlinePosition(m_platformData.ctFont());
// We need to adjust Times, Helvetica, and Courier to closely match the
// vertical metrics of their Microsoft counterparts that are the de facto
m_fontMetrics.setCapHeight(capHeight);
m_fontMetrics.setLineGap(lineGap);
m_fontMetrics.setXHeight(xHeight);
+ m_fontMetrics.setDecorationThickness(decorationThickness);
+ m_fontMetrics.setUnderlinePosition(underlinePosition);
}
static CFDataRef copyFontTableForTag(FontPlatformData& platformData, FourCharCode tableName)
float fDescent = -scaleEmToUnits(iDescent, unitsPerEm) * pointSize;
float fCapHeight = scaleEmToUnits(iCapHeight, unitsPerEm) * pointSize;
float fLineGap = scaleEmToUnits(iLineGap, unitsPerEm) * pointSize;
+ float decorationThickness;
+ float underlinePosition;
+ populateDecorationMetrics(m_platformData.size(), decorationThickness, underlinePosition);
if (!isCustomFont()) {
HWndDC dc(0);
m_fontMetrics.setCapHeight(fCapHeight);
m_fontMetrics.setLineGap(fLineGap);
m_fontMetrics.setLineSpacing(lroundf(fAscent) + lroundf(fDescent) + lroundf(fLineGap));
+ m_fontMetrics.setDecorationThickness(decorationThickness);
+ m_fontMetrics.setUnderlinePosition(underlinePosition);
GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page();
Glyph xGlyph = glyphPageZero ? glyphPageZero->glyphDataForCharacter('x').glyph : 0;
float descent = textMetrics.tmDescent * metricsMultiplier;
float xHeight = ascent * 0.56f; // Best guess for xHeight for non-Truetype fonts.
float lineGap = textMetrics.tmExternalLeading * metricsMultiplier;
+ float decorationThickness;
+ float underlinePosition;
+ populateDecorationMetrics(m_platformData.size(), decorationThickness, underlinePosition);
int faceLength = ::GetTextFace(dc, 0, 0);
Vector<WCHAR> faceName(faceLength);
m_fontMetrics.setDescent(descent);
m_fontMetrics.setLineGap(lineGap);
m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap));
+ m_fontMetrics.setDecorationThickness(decorationThickness);
+ m_fontMetrics.setUnderlinePosition(underlinePosition);
m_avgCharWidth = textMetrics.tmAveCharWidth * metricsMultiplier;
m_maxCharWidth = textMetrics.tmMaxCharWidth * metricsMultiplier;
float ascent = textMetrics.tmAscent;
float descent = textMetrics.tmDescent;
float lineGap = textMetrics.tmExternalLeading;
+ float decorationThickness;
+ float underlinePosition;
+ populateDecorationMetrics(m_platformData.size(), decorationThickness, underlinePosition);
m_fontMetrics.setAscent(ascent);
m_fontMetrics.setDescent(descent);
m_fontMetrics.setLineGap(lineGap);
m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap));
+ m_fontMetrics.setDecorationThickness(decorationThickness);
+ m_fontMetrics.setUnderlinePosition(underlinePosition);
m_avgCharWidth = textMetrics.tmAveCharWidth;
m_maxCharWidth = textMetrics.tmMaxCharWidth;
float xHeight = ascent * 0.56f; // Best guess for xHeight if no x glyph is present.
// Use a special function for underlines to get the positioning exactly right.
bool isPrinting = renderer().document().printing();
- float textDecorationThickness = textDecorationStrokeThickness(renderer().style().fontSize());
+ float textDecorationThickness = renderer().style().fontMetrics().decorationThickness();
context.setStrokeThickness(textDecorationThickness);
bool linesAreOpaque = !isPrinting && (!(decoration & TextDecorationUnderline) || underline.alpha() == 255) && (!(decoration & TextDecorationOverline) || overline.alpha() == 255) && (!(decoration & TextDecorationLineThrough) || linethrough.alpha() == 255);
// These decorations should match the visual overflows computed in visualOverflowForDecorations()
if (decoration & TextDecorationUnderline) {
context.setStrokeColor(underline, colorSpace);
- const int underlineOffset = computeUnderlineOffset(lineStyle.textUnderlinePosition(), lineStyle.fontMetrics(), this, textDecorationThickness);
+ const int underlineOffset = computeUnderlineOffset(lineStyle.textUnderlinePosition(), lineStyle.fontMetrics(), this);
switch (decorationStyle) {
case TextDecorationStyleWavy: {
namespace WebCore {
-int computeUnderlineOffset(TextUnderlinePosition underlinePosition, const FontMetrics& fontMetrics, InlineTextBox* inlineTextBox, int textDecorationThickness)
+int computeUnderlineOffset(TextUnderlinePosition underlinePosition, const FontMetrics& fontMetrics, InlineTextBox* inlineTextBox)
{
// This represents the gap between the baseline and the closest edge of the underline.
- int gap = std::max<int>(1, ceilf(textDecorationThickness / 2.0));
+ float gap = fontMetrics.underlinePosition();
// According to the specification TextUnderlinePositionAuto should default to 'alphabetic' for horizontal text
// and to 'under Left' for vertical text (e.g. japanese). We support only horizontal text for now.
if (decoration == TextDecorationNone)
return GlyphOverflow();
- float strokeThickness = textDecorationStrokeThickness(lineStyle.fontSize());
+ float strokeThickness = lineStyle.fontMetrics().decorationThickness();
float controlPointDistance;
float step;
float wavyOffset;
// These metrics must match where underlines get drawn.
if (decoration & TextDecorationUnderline) {
- float underlineOffset = computeUnderlineOffset(lineStyle.textUnderlinePosition(), lineStyle.fontMetrics(), inlineTextBox, strokeThickness);
+ float underlineOffset = computeUnderlineOffset(lineStyle.textUnderlinePosition(), lineStyle.fontMetrics(), inlineTextBox);
if (decorationStyle == TextDecorationStyleWavy) {
extendIntToFloat(overflowResult.bottom, underlineOffset + wavyOffset + controlPointDistance + strokeThickness - height);
extendIntToFloat(overflowResult.top, -(underlineOffset + wavyOffset - controlPointDistance - strokeThickness));
class InlineTextBox;
-inline float textDecorationStrokeThickness(float fontSize)
-{
- const float textDecorationBaseFontSize = 16;
- return fontSize / textDecorationBaseFontSize;
-}
-
inline float wavyOffsetFromDecoration()
{
return 2;
GlyphOverflow visualOverflowForDecorations(const RenderStyle& lineStyle, InlineTextBox*);
void getWavyStrokeParameters(float strokeThickness, float& controlPointDistance, float& step);
-int computeUnderlineOffset(TextUnderlinePosition, const FontMetrics&, InlineTextBox*, int textDecorationThickness);
+int computeUnderlineOffset(TextUnderlinePosition, const FontMetrics&, InlineTextBox*);
}
float ascent = svgFontFaceElement->ascent() * scale;
float descent = svgFontFaceElement->descent() * scale;
float lineGap = 0.1f * fontSize;
+ float decorationThickness;
+ float underlinePosition;
+ populateDecorationMetrics(fontSize, decorationThickness, underlinePosition);
GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(fontData, 0)->page();
fontMetrics.setLineGap(lineGap);
fontMetrics.setLineSpacing(roundf(ascent) + roundf(descent) + roundf(lineGap));
fontMetrics.setXHeight(xHeight);
+ fontMetrics.setDecorationThickness(decorationThickness);
+ fontMetrics.setUnderlinePosition(underlinePosition);
if (!glyphPageZero) {
fontData->setSpaceGlyph(0);