Add support for the initial-letter CSS property to first-letter
authorhyatt@apple.com <hyatt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 3 Sep 2014 19:26:38 +0000 (19:26 +0000)
committerhyatt@apple.com <hyatt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 3 Sep 2014 19:26:38 +0000 (19:26 +0000)
https://bugs.webkit.org/show_bug.cgi?id=136484

Reviewed by Dean Jackson.
Source/WebCore:

New tests in fast/css-generated-content/initial-letter-*.html

This patch add support for the CSS initial-letter property, enabling
better drop caps support in WebKit. Letters size to a specified number of
paragraph lines, and align to the cap-height of the first line and the baseline
of the last line.

* css/CSSComputedStyleDeclaration.cpp:
(WebCore::ComputedStyleExtractor::propertyValue):
Add -webkit-initial-letter to the list.

* css/CSSLineBoxContainValue.cpp:
(WebCore::CSSLineBoxContainValue::customCSSText):
* css/CSSLineBoxContainValue.h:
Add support for a new value of line-box-contain, initial-letter, that causes
lines to use cap-height above the baseline and the glyph bounds below the
baseline.

* css/CSSParser.cpp:
(WebCore::CSSParser::parseValue):
Add support for parsing of initial-letter.

(WebCore::CSSParser::parseLineBoxContain):
Add the new line-box-contain value for first-letters with initial-letter set.

* css/CSSPropertyNames.in:
Add the new initial-letter property.

* css/CSSValueKeywords.in:
Add the new initial-letter line-box-contain value.

* css/StyleResolver.cpp:
(WebCore::StyleResolver::applyProperty):
Map initial-letter into the RenderStyle.

* platform/graphics/FontMetrics.h:
(WebCore::FontMetrics::hasCapHeight):
(WebCore::FontMetrics::floatCapHeight):
(WebCore::FontMetrics::setCapHeight):
(WebCore::FontMetrics::capHeight):
* platform/graphics/ios/SimpleFontDataIOS.mm:
(WebCore::SimpleFontData::platformInit):
* platform/graphics/mac/SimpleFontDataMac.mm:
(WebCore::SimpleFontData::platformInit):
Add support for cap-height to the font system. iOS and Mac have been patched.
Other platforms will need to add support for cap-height to get this feature.
hasCapHeight() will return false for unsupported platforms for graceful
degradation.

* rendering/RenderBlock.cpp:
(WebCore::styleForFirstLetter):
Modified to check for initialLetterDrop/Height and to adjust the style
accordingly (e.g., to apply float when needed).

* rendering/RenderBlockFlow.cpp:
(WebCore::RenderBlockFlow::computeLogicalLocationForFloat):
Code to adjust the float's position and margin to do cap-height alignment
and sunken letters.

* rendering/RenderBlockFlow.h:
Remove the const from computeLogicalLocationForFloat, since the margin of the
float can now be modified dynamically for sunken first-letters.

* rendering/RootInlineBox.cpp:
(WebCore::RootInlineBox::ascentAndDescentForBox):
Add support for initial-letter line-box-contain value.

* rendering/RootInlineBox.h:
Add the includeInitialLetterForBox method to support the new line-box-contain value.

* rendering/style/RenderStyle.cpp:
(WebCore::RenderStyle::changeRequiresLayout):
* rendering/style/RenderStyle.h:
* rendering/style/StyleRareNonInheritedData.cpp:
(WebCore::StyleRareNonInheritedData::StyleRareNonInheritedData):
(WebCore::StyleRareNonInheritedData::operator==):
* rendering/style/StyleRareNonInheritedData.h:
Normal maintenance stuff for addition of a new CSS property (making sure it is diffed
properly for layout changes and copied on assignment, etc.)

LayoutTests:

* fast/css-generated-content/initial-letter-basic.html: Added.
* fast/css-generated-content/initial-letter-border-padding.html: Added.
* fast/css-generated-content/initial-letter-descender.html: Added.
* fast/css-generated-content/initial-letter-raised.html: Added.
* fast/css-generated-content/initial-letter-sunken.html: Added.
* platform/mac/fast/css-generated-content/initial-letter-basic-expected.png: Added.
* platform/mac/fast/css-generated-content/initial-letter-basic-expected.txt: Added.
* platform/mac/fast/css-generated-content/initial-letter-border-padding-expected.png: Added.
* platform/mac/fast/css-generated-content/initial-letter-border-padding-expected.txt: Added.
* platform/mac/fast/css-generated-content/initial-letter-descender-expected.png: Added.
* platform/mac/fast/css-generated-content/initial-letter-descender-expected.txt: Added.
* platform/mac/fast/css-generated-content/initial-letter-raised-expected.png: Added.
* platform/mac/fast/css-generated-content/initial-letter-raised-expected.txt: Added.
* platform/mac/fast/css-generated-content/initial-letter-sunken-expected.png: Added.
* platform/mac/fast/css-generated-content/initial-letter-sunken-expected.txt: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@173217 268f45cc-cd09-0410-ab3c-d52691b4dbfc

37 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/css-generated-content/initial-letter-basic.html [new file with mode: 0644]
LayoutTests/fast/css-generated-content/initial-letter-border-padding.html [new file with mode: 0644]
LayoutTests/fast/css-generated-content/initial-letter-descender.html [new file with mode: 0644]
LayoutTests/fast/css-generated-content/initial-letter-raised.html [new file with mode: 0644]
LayoutTests/fast/css-generated-content/initial-letter-sunken.html [new file with mode: 0644]
LayoutTests/platform/mac/fast/css-generated-content/initial-letter-basic-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/fast/css-generated-content/initial-letter-basic-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/fast/css-generated-content/initial-letter-border-padding-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/fast/css-generated-content/initial-letter-border-padding-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/fast/css-generated-content/initial-letter-descender-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/fast/css-generated-content/initial-letter-descender-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/fast/css-generated-content/initial-letter-raised-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/fast/css-generated-content/initial-letter-raised-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/fast/css-generated-content/initial-letter-sunken-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/fast/css-generated-content/initial-letter-sunken-expected.txt [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/css/CSSComputedStyleDeclaration.cpp
Source/WebCore/css/CSSLineBoxContainValue.cpp
Source/WebCore/css/CSSLineBoxContainValue.h
Source/WebCore/css/CSSParser.cpp
Source/WebCore/css/CSSPropertyNames.in
Source/WebCore/css/CSSValueKeywords.in
Source/WebCore/css/StyleResolver.cpp
Source/WebCore/platform/graphics/FontMetrics.h
Source/WebCore/platform/graphics/ios/SimpleFontDataIOS.mm
Source/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
Source/WebCore/rendering/RenderBlock.cpp
Source/WebCore/rendering/RenderBlockFlow.cpp
Source/WebCore/rendering/RenderBlockFlow.h
Source/WebCore/rendering/RenderBlockLineLayout.cpp
Source/WebCore/rendering/RootInlineBox.cpp
Source/WebCore/rendering/RootInlineBox.h
Source/WebCore/rendering/style/RenderStyle.cpp
Source/WebCore/rendering/style/RenderStyle.h
Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp
Source/WebCore/rendering/style/StyleRareNonInheritedData.h

index e4f9eec..6e214cc 100644 (file)
@@ -1,3 +1,26 @@
+2014-09-03  David Hyatt  <hyatt@apple.com>
+
+        Add support for the initial-letter CSS property to first-letter
+        https://bugs.webkit.org/show_bug.cgi?id=136484
+
+        Reviewed by Dean Jackson.
+
+        * fast/css-generated-content/initial-letter-basic.html: Added.
+        * fast/css-generated-content/initial-letter-border-padding.html: Added.
+        * fast/css-generated-content/initial-letter-descender.html: Added.
+        * fast/css-generated-content/initial-letter-raised.html: Added.
+        * fast/css-generated-content/initial-letter-sunken.html: Added.
+        * platform/mac/fast/css-generated-content/initial-letter-basic-expected.png: Added.
+        * platform/mac/fast/css-generated-content/initial-letter-basic-expected.txt: Added.
+        * platform/mac/fast/css-generated-content/initial-letter-border-padding-expected.png: Added.
+        * platform/mac/fast/css-generated-content/initial-letter-border-padding-expected.txt: Added.
+        * platform/mac/fast/css-generated-content/initial-letter-descender-expected.png: Added.
+        * platform/mac/fast/css-generated-content/initial-letter-descender-expected.txt: Added.
+        * platform/mac/fast/css-generated-content/initial-letter-raised-expected.png: Added.
+        * platform/mac/fast/css-generated-content/initial-letter-raised-expected.txt: Added.
+        * platform/mac/fast/css-generated-content/initial-letter-sunken-expected.png: Added.
+        * platform/mac/fast/css-generated-content/initial-letter-sunken-expected.txt: Added.
+
 2014-09-03  Brent Fulgham  <bfulgham@apple.com>
 
         [Win] Unreviewed test gardening.
diff --git a/LayoutTests/fast/css-generated-content/initial-letter-basic.html b/LayoutTests/fast/css-generated-content/initial-letter-basic.html
new file mode 100644 (file)
index 0000000..13f474b
--- /dev/null
@@ -0,0 +1,23 @@
+<html>
+<head>
+<style>
+div { width:400px; margin:1em }
+div::first-letter { -webkit-initial-letter: 3; margin-right:2px; margin-left:2px }
+span.rtl { direction:rtl; display:block }
+</style>
+</head>
+<div>
+An example of first-letter. This letter should span 3 lines of text, and
+so it should align itself cleanly with the cap-height of the A lining up with
+the cap-height of the first line, and the baseline of the A lining up with the
+baseline of the third line.
+</div>
+<span class="rtl" >
+<div>An RTL example of first-letter. This letter should span 3 lines of text, and
+so it should align itself cleanly with the cap-height of the A lining up with
+the cap-height of the first line, and the baseline of the A lining up with the
+baseline of the third line.
+</div>
+</span>
+
+
diff --git a/LayoutTests/fast/css-generated-content/initial-letter-border-padding.html b/LayoutTests/fast/css-generated-content/initial-letter-border-padding.html
new file mode 100644 (file)
index 0000000..71cad9f
--- /dev/null
@@ -0,0 +1,23 @@
+<html>
+<head>
+<style>
+div { width:400px; margin:1em }
+div::first-letter { color:red; border:2px solid red; padding:1px; -webkit-initial-letter: 2 3; margin-right:2px; margin-left:2px }
+span.rtl { direction:rtl; display:block }
+</style>
+</head>
+<div>
+An example of first-letter. This letter should span 3 lines of text, and
+so it should align itself cleanly with the cap-height of the A lining up with
+the cap-height of the first line, and the baseline of the A lining up with the
+baseline of the third line.
+</div>
+<span class="rtl" >
+<div>An RTL example of first-letter. This letter should span 3 lines of text, and
+so it should align itself cleanly with the cap-height of the A lining up with
+the cap-height of the first line, and the baseline of the A lining up with the
+baseline of the third line.
+</div>
+</span>
+
+
diff --git a/LayoutTests/fast/css-generated-content/initial-letter-descender.html b/LayoutTests/fast/css-generated-content/initial-letter-descender.html
new file mode 100644 (file)
index 0000000..5650cdd
--- /dev/null
@@ -0,0 +1,14 @@
+<html>
+<head>
+<style>
+div { width:400px; margin:1em }
+div::first-letter { font-family: Zapfino; -webkit-initial-letter: 2 4; margin-right:2px; margin-left:2 }
+
+</style>
+</head>
+<div>
+Just an example of first-letter. This letter should span 3 lines of text, and
+so it should align itself cleanly with the cap-height of the H lining up with
+the cap-height of the first line, and the baseline of the J lining up with the
+baseline of the third line. The descender of the J is still avoided by following lines.
+</div>
diff --git a/LayoutTests/fast/css-generated-content/initial-letter-raised.html b/LayoutTests/fast/css-generated-content/initial-letter-raised.html
new file mode 100644 (file)
index 0000000..8f2734b
--- /dev/null
@@ -0,0 +1,23 @@
+<html>
+<head>
+<style>
+div { width:400px; margin:1em }
+div::first-letter { -webkit-initial-letter: 2 3; margin-right:2px; margin-left:2px }
+span.rtl { direction:rtl; display:block }
+</style>
+</head>
+<div>
+An example of first-letter. This letter should span 3 lines of text, and
+so it should align itself cleanly with the cap-height of the A lining up with
+the cap-height of the first line, and the baseline of the A lining up with the
+baseline of the third line.
+</div>
+<span class="rtl" >
+<div>An RTL example of first-letter. This letter should span 3 lines of text, and
+so it should align itself cleanly with the cap-height of the A lining up with
+the cap-height of the first line, and the baseline of the A lining up with the
+baseline of the third line.
+</div>
+</span>
+
+
diff --git a/LayoutTests/fast/css-generated-content/initial-letter-sunken.html b/LayoutTests/fast/css-generated-content/initial-letter-sunken.html
new file mode 100644 (file)
index 0000000..cff67d7
--- /dev/null
@@ -0,0 +1,23 @@
+<html>
+<head>
+<style>
+div { width:400px; margin:1em }
+div::first-letter { -webkit-initial-letter: 3 2; margin-right:2px; margin-left:2px }
+span.rtl { direction:rtl; display:block }
+</style>
+</head>
+<div>
+An example of first-letter. This letter should span 3 lines of text, and
+so it should align itself cleanly with the cap-height of the A lining up with
+the cap-height of the first line, and the baseline of the A lining up with the
+baseline of the third line.
+</div>
+<span class="rtl" >
+<div>An RTL example of first-letter. This letter should span 3 lines of text, and
+so it should align itself cleanly with the cap-height of the A lining up with
+the cap-height of the first line, and the baseline of the A lining up with the
+baseline of the third line.
+</div>
+</span>
+
+
diff --git a/LayoutTests/platform/mac/fast/css-generated-content/initial-letter-basic-expected.png b/LayoutTests/platform/mac/fast/css-generated-content/initial-letter-basic-expected.png
new file mode 100644 (file)
index 0000000..230d710
Binary files /dev/null and b/LayoutTests/platform/mac/fast/css-generated-content/initial-letter-basic-expected.png differ
diff --git a/LayoutTests/platform/mac/fast/css-generated-content/initial-letter-basic-expected.txt b/LayoutTests/platform/mac/fast/css-generated-content/initial-letter-basic-expected.txt
new file mode 100644 (file)
index 0000000..ad914d5
--- /dev/null
@@ -0,0 +1,27 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,16) size 784x568
+      RenderBlock {DIV} at (16,0) size 400x90
+        RenderBlock (floating) at (2,3) size 51x48
+          RenderText {#text} at (0,-17) size 51x82
+            text run at (0,-17) width 51: "A"
+        RenderText {#text} at (55,0) size 444x90
+          text run at (55,0) width 389: "n example of first-letter. This letter should span 3 lines of text,"
+          text run at (55,18) width 342: "and so it should align itself cleanly with the cap-height"
+          text run at (55,36) width 336: "of the A lining up with the cap-height of the first line,"
+          text run at (0,54) width 400: "and the baseline of the A lining up with the baseline of the third"
+          text run at (0,72) width 27: "line."
+      RenderBlock {SPAN} at (0,106) size 784x90
+        RenderBlock {DIV} at (368,0) size 400x90
+          RenderBlock (floating) at (347,3) size 51x48
+            RenderText {#text} at (0,-17) size 51x82
+              text run at (0,-17) width 51: "A"
+          RenderText {#text} at (-48,0) size 448x90
+            text run at (-48,0) width 393: "n RTL example of first-letter. This letter should span 3 lines of"
+            text run at (11,18) width 334: "text, and so it should align itself cleanly with the cap-"
+            text run at (25,36) width 320: "height of the A lining up with the cap-height of the"
+            text run at (14,54) width 386: "first line, and the baseline of the A lining up with the baseline"
+            text run at (300,72) width 4 RTL: "."
+            text run at (304,72) width 96: "of the third line"
diff --git a/LayoutTests/platform/mac/fast/css-generated-content/initial-letter-border-padding-expected.png b/LayoutTests/platform/mac/fast/css-generated-content/initial-letter-border-padding-expected.png
new file mode 100644 (file)
index 0000000..74cd174
Binary files /dev/null and b/LayoutTests/platform/mac/fast/css-generated-content/initial-letter-border-padding-expected.png differ
diff --git a/LayoutTests/platform/mac/fast/css-generated-content/initial-letter-border-padding-expected.txt b/LayoutTests/platform/mac/fast/css-generated-content/initial-letter-border-padding-expected.txt
new file mode 100644 (file)
index 0000000..e7703a1
--- /dev/null
@@ -0,0 +1,27 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,16) size 784x568
+      RenderBlock {DIV} at (16,0) size 400x108
+        RenderBlock (floating) at (2,0) size 57x54 [color=#FF0000] [border: (2px solid #FF0000)]
+          RenderText {#text} at (3,-14) size 51x82
+            text run at (3,-14) width 51: "A"
+        RenderText {#text} at (61,18) size 398x90
+          text run at (61,18) width 308: "n example of first-letter. This letter should span 3"
+          text run at (61,36) width 330: "lines of text, and so it should align itself cleanly with"
+          text run at (0,54) width 398: "the cap-height of the A lining up with the cap-height of the first"
+          text run at (0,72) width 398: "line, and the baseline of the A lining up with the baseline of the"
+          text run at (0,90) width 60: "third line."
+      RenderBlock {SPAN} at (0,124) size 784x108
+        RenderBlock {DIV} at (368,0) size 400x108
+          RenderBlock (floating) at (341,0) size 57x54 [color=#FF0000] [border: (2px solid #FF0000)]
+            RenderText {#text} at (3,-14) size 51x82
+              text run at (3,-14) width 51: "A"
+          RenderText {#text} at (8,18) size 392x90
+            text run at (8,18) width 331: "n RTL example of first-letter. This letter should span"
+            text run at (29,36) width 310: "3 lines of text, and so it should align itself cleanly"
+            text run at (21,54) width 379: "with the cap-height of the A lining up with the cap-height of"
+            text run at (46,72) width 354: "the first line, and the baseline of the A lining up with the"
+            text run at (245,90) width 4 RTL: "."
+            text run at (249,90) width 151: "baseline of the third line"
diff --git a/LayoutTests/platform/mac/fast/css-generated-content/initial-letter-descender-expected.png b/LayoutTests/platform/mac/fast/css-generated-content/initial-letter-descender-expected.png
new file mode 100644 (file)
index 0000000..ed3db2d
Binary files /dev/null and b/LayoutTests/platform/mac/fast/css-generated-content/initial-letter-descender-expected.png differ
diff --git a/LayoutTests/platform/mac/fast/css-generated-content/initial-letter-descender-expected.txt b/LayoutTests/platform/mac/fast/css-generated-content/initial-letter-descender-expected.txt
new file mode 100644 (file)
index 0000000..73a3c27
--- /dev/null
@@ -0,0 +1,16 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,16) size 784x568
+      RenderBlock {DIV} at (16,0) size 400x144
+        RenderBlock (floating) at (2,3) size 48x81
+          RenderText {#text} at (0,-46) size 48x200
+            text run at (0,-46) width 48: "J"
+        RenderText {#text} at (52,36) size 399x108
+          text run at (52,36) width 337: "ust an example of first-letter. This letter should span 3"
+          text run at (52,54) width 330: "lines of text, and so it should align itself cleanly with"
+          text run at (52,72) width 347: "the cap-height of the H lining up with the cap-height of"
+          text run at (0,90) width 348: "the first line, and the baseline of the J lining up with the"
+          text run at (0,108) width 395: "baseline of the third line. The descender of the J is still avoided"
+          text run at (0,126) width 118: "by following lines."
diff --git a/LayoutTests/platform/mac/fast/css-generated-content/initial-letter-raised-expected.png b/LayoutTests/platform/mac/fast/css-generated-content/initial-letter-raised-expected.png
new file mode 100644 (file)
index 0000000..e5bd0ae
Binary files /dev/null and b/LayoutTests/platform/mac/fast/css-generated-content/initial-letter-raised-expected.png differ
diff --git a/LayoutTests/platform/mac/fast/css-generated-content/initial-letter-raised-expected.txt b/LayoutTests/platform/mac/fast/css-generated-content/initial-letter-raised-expected.txt
new file mode 100644 (file)
index 0000000..102a6cb
--- /dev/null
@@ -0,0 +1,27 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,16) size 784x568
+      RenderBlock {DIV} at (16,0) size 400x108
+        RenderBlock (floating) at (2,3) size 51x48
+          RenderText {#text} at (0,-17) size 51x82
+            text run at (0,-17) width 51: "A"
+        RenderText {#text} at (55,18) size 398x90
+          text run at (55,18) width 341: "n example of first-letter. This letter should span 3 lines"
+          text run at (55,36) width 320: "of text, and so it should align itself cleanly with the"
+          text run at (0,54) width 375: "cap-height of the A lining up with the cap-height of the first"
+          text run at (0,72) width 398: "line, and the baseline of the A lining up with the baseline of the"
+          text run at (0,90) width 60: "third line."
+      RenderBlock {SPAN} at (0,124) size 784x108
+        RenderBlock {DIV} at (368,0) size 400x108
+          RenderBlock (floating) at (347,3) size 51x48
+            RenderText {#text} at (0,-17) size 51x82
+              text run at (0,-17) width 51: "A"
+          RenderText {#text} at (2,18) size 398x90
+            text run at (2,18) width 343: "n RTL example of first-letter. This letter should span 3"
+            text run at (15,36) width 330: "lines of text, and so it should align itself cleanly with"
+            text run at (2,54) width 398: "the cap-height of the A lining up with the cap-height of the first"
+            text run at (2,72) width 398: "line, and the baseline of the A lining up with the baseline of the"
+            text run at (340,90) width 4 RTL: "."
+            text run at (344,90) width 56: "third line"
diff --git a/LayoutTests/platform/mac/fast/css-generated-content/initial-letter-sunken-expected.png b/LayoutTests/platform/mac/fast/css-generated-content/initial-letter-sunken-expected.png
new file mode 100644 (file)
index 0000000..342a4cc
Binary files /dev/null and b/LayoutTests/platform/mac/fast/css-generated-content/initial-letter-sunken-expected.png differ
diff --git a/LayoutTests/platform/mac/fast/css-generated-content/initial-letter-sunken-expected.txt b/LayoutTests/platform/mac/fast/css-generated-content/initial-letter-sunken-expected.txt
new file mode 100644 (file)
index 0000000..b508b9e
--- /dev/null
@@ -0,0 +1,27 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,16) size 784x568
+      RenderBlock {DIV} at (16,0) size 400x90
+        RenderBlock (floating) at (2,21) size 31x30
+          RenderText {#text} at (0,-9) size 31x49
+            text run at (0,-9) width 31: "A"
+        RenderText {#text} at (35,0) size 398x90
+          text run at (35,0) width 358: "n example of first-letter. This letter should span 3 lines of"
+          text run at (35,18) width 334: "text, and so it should align itself cleanly with the cap-"
+          text run at (35,36) width 348: "height of the A lining up with the cap-height of the first"
+          text run at (0,54) width 398: "line, and the baseline of the A lining up with the baseline of the"
+          text run at (0,72) width 60: "third line."
+      RenderBlock {SPAN} at (0,106) size 784x90
+        RenderBlock {DIV} at (368,0) size 400x90
+          RenderBlock (floating) at (367,21) size 31x30
+            RenderText {#text} at (0,-9) size 31x49
+              text run at (0,-9) width 31: "A"
+          RenderText {#text} at (22,0) size 388x90
+            text run at (22,0) width 343: "n RTL example of first-letter. This letter should span 3"
+            text run at (12,18) width 353: "lines of text, and so it should align itself cleanly with the"
+            text run at (18,36) width 347: "cap-height of the A lining up with the cap-height of the"
+            text run at (14,54) width 386: "first line, and the baseline of the A lining up with the baseline"
+            text run at (300,72) width 4 RTL: "."
+            text run at (304,72) width 96: "of the third line"
index f5ec618..b72e1be 100644 (file)
@@ -1,3 +1,90 @@
+2014-09-03  David Hyatt  <hyatt@apple.com>
+
+        Add support for the initial-letter CSS property to first-letter
+        https://bugs.webkit.org/show_bug.cgi?id=136484
+
+        Reviewed by Dean Jackson.
+        
+        New tests in fast/css-generated-content/initial-letter-*.html
+
+        This patch add support for the CSS initial-letter property, enabling
+        better drop caps support in WebKit. Letters size to a specified number of
+        paragraph lines, and align to the cap-height of the first line and the baseline
+        of the last line.
+
+        * css/CSSComputedStyleDeclaration.cpp:
+        (WebCore::ComputedStyleExtractor::propertyValue):
+        Add -webkit-initial-letter to the list.
+
+        * css/CSSLineBoxContainValue.cpp:
+        (WebCore::CSSLineBoxContainValue::customCSSText):
+        * css/CSSLineBoxContainValue.h:
+        Add support for a new value of line-box-contain, initial-letter, that causes
+        lines to use cap-height above the baseline and the glyph bounds below the
+        baseline.
+
+        * css/CSSParser.cpp:
+        (WebCore::CSSParser::parseValue):
+        Add support for parsing of initial-letter.
+
+        (WebCore::CSSParser::parseLineBoxContain):
+        Add the new line-box-contain value for first-letters with initial-letter set.
+
+        * css/CSSPropertyNames.in:
+        Add the new initial-letter property.
+
+        * css/CSSValueKeywords.in:
+        Add the new initial-letter line-box-contain value.
+
+        * css/StyleResolver.cpp:
+        (WebCore::StyleResolver::applyProperty):
+        Map initial-letter into the RenderStyle.
+
+        * platform/graphics/FontMetrics.h:
+        (WebCore::FontMetrics::hasCapHeight):
+        (WebCore::FontMetrics::floatCapHeight):
+        (WebCore::FontMetrics::setCapHeight):
+        (WebCore::FontMetrics::capHeight):
+        * platform/graphics/ios/SimpleFontDataIOS.mm:
+        (WebCore::SimpleFontData::platformInit):
+        * platform/graphics/mac/SimpleFontDataMac.mm:
+        (WebCore::SimpleFontData::platformInit):
+        Add support for cap-height to the font system. iOS and Mac have been patched.
+        Other platforms will need to add support for cap-height to get this feature.
+        hasCapHeight() will return false for unsupported platforms for graceful
+        degradation.
+
+        * rendering/RenderBlock.cpp:
+        (WebCore::styleForFirstLetter):
+        Modified to check for initialLetterDrop/Height and to adjust the style
+        accordingly (e.g., to apply float when needed).
+
+        * rendering/RenderBlockFlow.cpp:
+        (WebCore::RenderBlockFlow::computeLogicalLocationForFloat):
+        Code to adjust the float's position and margin to do cap-height alignment
+        and sunken letters.
+
+        * rendering/RenderBlockFlow.h:
+        Remove the const from computeLogicalLocationForFloat, since the margin of the
+        float can now be modified dynamically for sunken first-letters.
+
+        * rendering/RootInlineBox.cpp:
+        (WebCore::RootInlineBox::ascentAndDescentForBox):
+        Add support for initial-letter line-box-contain value.
+
+        * rendering/RootInlineBox.h:
+        Add the includeInitialLetterForBox method to support the new line-box-contain value.
+
+        * rendering/style/RenderStyle.cpp:
+        (WebCore::RenderStyle::changeRequiresLayout):
+        * rendering/style/RenderStyle.h:
+        * rendering/style/StyleRareNonInheritedData.cpp:
+        (WebCore::StyleRareNonInheritedData::StyleRareNonInheritedData):
+        (WebCore::StyleRareNonInheritedData::operator==):
+        * rendering/style/StyleRareNonInheritedData.h:
+        Normal maintenance stuff for addition of a new CSS property (making sure it is diffed
+        properly for layout changes and copied on assignment, etc.)
+
 2014-09-03  Brent Fulgham  <bfulgham@apple.com>
 
         [Win] Prevent double-release on AVCFURLAssetRef
index 7bcd34a..e81e3d4 100644 (file)
@@ -316,6 +316,7 @@ static const CSSPropertyID computedProperties[] = {
     CSSPropertyWebkitHyphenateLimitBefore,
     CSSPropertyWebkitHyphenateLimitLines,
     CSSPropertyWebkitHyphens,
+    CSSPropertyWebkitInitialLetter,
     CSSPropertyWebkitLineAlign,
     CSSPropertyWebkitLineBoxContain,
     CSSPropertyWebkitLineBreak,
@@ -2709,6 +2710,11 @@ PassRefPtr<CSSValue> ComputedStyleExtractor::propertyValue(CSSPropertyID propert
         case CSSPropertyWebkitFontSizeDelta:
             // Not a real style property -- used by the editing engine -- so has no computed value.
             break;
+        case CSSPropertyWebkitInitialLetter: {
+            RefPtr<CSSPrimitiveValue> drop = !style->initialLetterDrop() ? cssValuePool().createIdentifierValue(CSSValueNormal) : cssValuePool().createValue(style->initialLetterDrop(), CSSPrimitiveValue::CSS_NUMBER);
+            RefPtr<CSSPrimitiveValue> size = !style->initialLetterHeight() ? cssValuePool().createIdentifierValue(CSSValueNormal) : cssValuePool().createValue(style->initialLetterHeight(), CSSPrimitiveValue::CSS_NUMBER);
+            return cssValuePool().createValue(Pair::create(drop.release(), size.release()));
+        }
         case CSSPropertyWebkitMarginBottomCollapse:
         case CSSPropertyWebkitMarginAfterCollapse:
             return cssValuePool().createValue(style->marginAfterCollapse());
index 07fb17a..19fdf8b 100644 (file)
@@ -67,6 +67,11 @@ String CSSLineBoxContainValue::customCSSText() const
             text.append(' ');
         text.appendLiteral("inline-box");
     }
+    if (m_value & LineBoxContainInitialLetter) {
+        if (!text.isEmpty())
+            text.append(' ');
+        text.appendLiteral("initial-letter");
+    }
 
     return text.toString();
 }
index fa3aefd..b980e8e 100644 (file)
@@ -35,7 +35,7 @@ namespace WebCore {
 class CSSPrimitiveValue;
 
 enum LineBoxContainFlags { LineBoxContainNone = 0x0, LineBoxContainBlock = 0x1, LineBoxContainInline = 0x2, LineBoxContainFont = 0x4, LineBoxContainGlyphs = 0x8,
-                           LineBoxContainReplaced = 0x10, LineBoxContainInlineBox = 0x20 };
+                           LineBoxContainReplaced = 0x10, LineBoxContainInlineBox = 0x20, LineBoxContainInitialLetter = 0x40 };
 typedef unsigned LineBoxContain;
 
 // Used for text-CSSLineBoxContain and box-CSSLineBoxContain
index 32e1db9..c7e78ca 100644 (file)
@@ -2414,6 +2414,30 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important)
             return false;
         }
         break;
+    case CSSPropertyWebkitInitialLetter: {
+        if (id == CSSValueNormal)
+            validPrimitive = true;
+        else {
+            if (num != 1 && num != 2)
+                return false;
+            validPrimitive = validUnit(value, FPositiveInteger);
+            if (!validPrimitive)
+                return false;
+            RefPtr<CSSPrimitiveValue> parsedValue1 = createPrimitiveNumericValue(value);
+            RefPtr<CSSPrimitiveValue> parsedValue2;
+            if (num == 2) {
+                value = m_valueList->next();
+                validPrimitive = validUnit(value, FPositiveInteger);
+                if (!validPrimitive)
+                    return false;
+                parsedValue2 = createPrimitiveNumericValue(value);
+            } else
+                parsedValue2 = parsedValue1;
+            addProperty(propId, createPrimitiveValuePair(parsedValue1.release(), parsedValue2.release()), important);
+            return true;
+        }
+        break;
+    }
     case CSSPropertyWebkitBoxReflect:
         if (id == CSSValueNone)
             validPrimitive = true;
@@ -9836,6 +9860,10 @@ bool CSSParser::parseLineBoxContain(bool important)
             if (lineBoxContain & LineBoxContainInlineBox)
                 return false;
             lineBoxContain |= LineBoxContainInlineBox;
+        } else if (value->id == CSSValueInitialLetter) {
+            if (lineBoxContain & LineBoxContainInitialLetter)
+                return false;
+            lineBoxContain |= LineBoxContainInitialLetter;
         } else
             return false;
     }
index 5af3f5f..22fa804 100644 (file)
@@ -331,6 +331,7 @@ isolation
 -webkit-hyphenate-limit-lines [Inherited]
 -webkit-hyphens [Inherited]
 -epub-hyphens = -webkit-hyphens
+-webkit-initial-letter
 -webkit-line-box-contain [Inherited]
 -webkit-line-align [Inherited]
 -webkit-line-break [Inherited]
index ff6dcda..b5d5c92 100644 (file)
@@ -971,6 +971,7 @@ vertical-right
 font
 glyphs
 inline-box
+initial-letter
 replaced
 
 // -webkit-font-feature-settings
index e923609..70b8bc6 100644 (file)
@@ -2944,6 +2944,25 @@ void StyleResolver::applyProperty(CSSPropertyID id, CSSValue* value)
         state.style()->setScrollSnapCoordinates(coordinates);
         return;
     }
+    case CSSPropertyWebkitInitialLetter: {
+        HANDLE_INHERIT_AND_INITIAL(initialLetter, InitialLetter)
+        if (!value->isPrimitiveValue())
+            return;
+        
+        if (primitiveValue->getValueID() == CSSValueNormal) {
+            state.style()->setInitialLetter(IntSize());
+            return;
+        }
+            
+        CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
+        Pair* pair = primitiveValue->getPairValue();
+        if (!pair || !pair->first() || !pair->second())
+            return;
+
+        state.style()->setInitialLetter(IntSize(pair->first()->getIntValue(), pair->second()->getIntValue()));
+        return;
+    }
+    
 #endif
     // These properties are aliased and DeprecatedStyleBuilder already applied the property on the prefixed version.
     case CSSPropertyTransitionDelay:
index 5142ffe..a1eac37 100644 (file)
@@ -83,7 +83,15 @@ public:
 
     bool hasXHeight() const { return m_hasXHeight && m_xHeight > 0; }
     void setHasXHeight(bool hasXHeight) { m_hasXHeight = hasXHeight; }
-
+    
+    bool hasCapHeight() const { return m_hasCapHeight && m_capHeight > 0; }
+    float floatCapHeight() const { return m_capHeight; }
+    void setCapHeight(float capHeight)
+    { 
+        m_capHeight = capHeight;
+        m_hasCapHeight = true;
+    }
+    
     // Integer variants of certain metrics, used for HTML rendering.
     int ascent(FontBaseline baselineType = AlphabeticBaseline) const
     {
@@ -91,7 +99,7 @@ public:
             return lroundf(m_ascent);
         return height() - height() / 2;
     }
-
+    
     int descent(FontBaseline baselineType = AlphabeticBaseline) const
     {
         if (baselineType == AlphabeticBaseline)
@@ -106,7 +114,9 @@ public:
 
     int lineGap() const { return lroundf(m_lineGap); }
     int lineSpacing() const { return lroundf(m_lineSpacing); }
-
+    
+    int capHeight() const { return lroundf(m_capHeight); }
+    
     bool hasIdenticalAscentDescentAndLineGap(const FontMetrics& other) const
     {
         return ascent() == other.ascent() && descent() == other.descent() && lineGap() == other.lineGap();
@@ -142,8 +152,10 @@ private:
     float m_lineGap;
     float m_lineSpacing;
     float m_xHeight;
+    float m_capHeight;
     float m_zeroWidth;
     bool m_hasXHeight;
+    bool m_hasCapHeight;
     bool m_hasZeroWidth;
 };
 
index d3ac1a5..4af8a23 100644 (file)
@@ -75,6 +75,7 @@ void SimpleFontData::platformInit()
     unsigned unitsPerEm;
     float ascent;
     float descent;
+    float capHeight;
     float lineGap;
     float lineSpacing;
     float xHeight;
@@ -86,6 +87,7 @@ void SimpleFontData::platformInit()
         lineSpacing = fontService.lineSpacing();
         lineGap = fontService.lineGap();
         xHeight = fontService.xHeight();
+        capHeight = fontService.capHeight();
         unitsPerEm = fontService.unitsPerEm();
         familyName = adoptCF(CTFontCopyFamilyName(ctFont));
     } else {
@@ -98,6 +100,7 @@ void SimpleFontData::platformInit()
         descent = lroundf(-scaleEmToUnits(-abs(CGFontGetDescent(cgFont)), unitsPerEm) * pointSize);
         lineGap = lroundf(scaleEmToUnits(CGFontGetLeading(cgFont), unitsPerEm) * pointSize);
         xHeight = scaleEmToUnits(CGFontGetXHeight(cgFont), unitsPerEm) * pointSize;
+        capHeight = scaleEmToUnits(CGFontGetCapHeight(cgFont), unitsPerEm) * pointSize;
 
         lineSpacing = ascent + descent + lineGap;
         familyName = adoptCF(CGFontCopyFamilyName(cgFont));
@@ -109,6 +112,7 @@ void SimpleFontData::platformInit()
     m_fontMetrics.setLineGap(lineGap);
     m_fontMetrics.setLineSpacing(lineSpacing);
     m_fontMetrics.setXHeight(xHeight);
+    m_fontMetrics.setCapHeight(capHeight);
     m_shouldNotBeUsedForArabic = fontFamilyShouldNotBeUsedForArabic(familyName.get());
 
     if (platformData().orientation() == Vertical && !isTextOrientationFallback())
index f904152..fbdc744 100644 (file)
@@ -186,18 +186,22 @@ void SimpleFontData::platformInit()
     
     int iAscent;
     int iDescent;
+    int iCapHeight;
     int iLineGap;
     unsigned unitsPerEm;
     iAscent = CGFontGetAscent(m_platformData.cgFont());
     // Some fonts erroneously specify a positive descender value. We follow Core Text in assuming that
     // such fonts meant the same distance, but in the reverse direction.
     iDescent = -abs(CGFontGetDescent(m_platformData.cgFont()));
+    iCapHeight = CGFontGetCapHeight(m_platformData.cgFont());
     iLineGap = CGFontGetLeading(m_platformData.cgFont());
     unitsPerEm = CGFontGetUnitsPerEm(m_platformData.cgFont());
 
     float pointSize = m_platformData.m_size;
     float ascent = scaleEmToUnits(iAscent, unitsPerEm) * pointSize;
     float descent = -scaleEmToUnits(iDescent, unitsPerEm) * pointSize;
+    float capHeight = scaleEmToUnits(iCapHeight, unitsPerEm) * pointSize;
+    
     float lineGap = scaleEmToUnits(iLineGap, unitsPerEm) * pointSize;
 
     // We need to adjust Times, Helvetica, and Courier to closely match the
@@ -239,6 +243,7 @@ void SimpleFontData::platformInit()
     m_fontMetrics.setUnitsPerEm(unitsPerEm);
     m_fontMetrics.setAscent(ascent);
     m_fontMetrics.setDescent(descent);
+    m_fontMetrics.setCapHeight(capHeight);
     m_fontMetrics.setLineGap(lineGap);
     m_fontMetrics.setXHeight(xHeight);
 }
index 34bbe03..bc8175b 100644 (file)
@@ -3453,6 +3453,44 @@ RenderBlock* RenderBlock::firstLineBlock() const
 static RenderStyle* styleForFirstLetter(RenderObject* firstLetterBlock, RenderObject* firstLetterContainer)
 {
     RenderStyle* pseudoStyle = firstLetterBlock->getCachedPseudoStyle(FIRST_LETTER, &firstLetterContainer->firstLineStyle());
+    
+    // If we have an initial letter drop that is >= 1, then we need to force floating to be on.
+    if (pseudoStyle->initialLetterDrop() >= 1 && !pseudoStyle->isFloating())
+        pseudoStyle->setFloating(pseudoStyle->isLeftToRightDirection() ? LeftFloat : RightFloat);
+
+    // We have to compute the correct font-size for the first-letter if it has an initial letter height set.
+    RenderObject* paragraph = firstLetterContainer->isRenderBlockFlow() ? firstLetterContainer : firstLetterContainer->containingBlock();
+    if (pseudoStyle->initialLetterHeight() >= 1 && pseudoStyle->fontMetrics().hasCapHeight() && paragraph->style().fontMetrics().hasCapHeight()) {
+        // FIXME: For ideographic baselines, we want to go from line edge to line edge. This is equivalent to (N-1)*line-height + the font height.
+        // We don't yet support ideographic baselines.
+        // For an N-line first-letter and for alphabetic baselines, the cap-height of the first letter needs to equal (N-1)*line-height of paragraph lines + cap-height of the paragraph
+        // Mathematically we can't rely on font-size, since font().height() doesn't necessarily match. For reliability, the best approach is simply to
+        // compare the final measured cap-heights of the two fonts in order to get to the closest possible value.
+        pseudoStyle->setLineBoxContain(LineBoxContainInitialLetter);
+        int lineHeight = paragraph->style().computedLineHeight();
+        
+        // Set the font to be one line too big and then ratchet back to get to a precise fit. We can't just set the desired font size based off font height metrics
+        // because many fonts bake ascent into the font metrics. Therefore we have to look at actual measured cap height values in order to know when we have a good fit.
+        FontDescription newFontDescription = pseudoStyle->fontDescription();
+        float capRatio = pseudoStyle->fontMetrics().floatCapHeight() / pseudoStyle->fontSize();
+        float startingFontSize = ((pseudoStyle->initialLetterHeight() - 1) * lineHeight + paragraph->style().fontMetrics().capHeight()) / capRatio;
+        newFontDescription.setSpecifiedSize(startingFontSize);
+        newFontDescription.setComputedSize(startingFontSize);
+        pseudoStyle->setFontDescription(newFontDescription);
+        pseudoStyle->font().update(pseudoStyle->font().fontSelector());
+        
+        int desiredCapHeight = (pseudoStyle->initialLetterHeight() - 1) * lineHeight + paragraph->style().fontMetrics().capHeight();
+        int actualCapHeight = pseudoStyle->fontMetrics().capHeight();
+        while (actualCapHeight > desiredCapHeight) {
+            FontDescription newFontDescription = pseudoStyle->fontDescription();
+            newFontDescription.setSpecifiedSize(newFontDescription.specifiedSize() - 1);
+            newFontDescription.setComputedSize(newFontDescription.computedSize() -1);
+            pseudoStyle->setFontDescription(newFontDescription);
+            pseudoStyle->font().update(pseudoStyle->font().fontSelector());
+            actualCapHeight = pseudoStyle->fontMetrics().capHeight();
+        }
+    }
+    
     // Force inline display (except for floating first-letters).
     pseudoStyle->setDisplay(pseudoStyle->isFloating() ? BLOCK : INLINE);
     // CSS2 says first-letter can't be positioned.
index 5d95f3e..61e7ca6 100644 (file)
@@ -2290,7 +2290,7 @@ LayoutUnit RenderBlockFlow::logicalRightOffsetForPositioningFloat(LayoutUnit log
     return adjustLogicalRightOffsetForLine(offset, applyTextIndent);
 }
 
-LayoutPoint RenderBlockFlow::computeLogicalLocationForFloat(const FloatingObject* floatingObject, LayoutUnit logicalTopOffset) const
+LayoutPoint RenderBlockFlow::computeLogicalLocationForFloat(const FloatingObject* floatingObject, LayoutUnit logicalTopOffset)
 {
     RenderBox& childBox = floatingObject->renderer();
     LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
@@ -2337,6 +2337,34 @@ LayoutPoint RenderBlockFlow::computeLogicalLocationForFloat(const FloatingObject
         floatLogicalLeft -= logicalWidthForFloat(floatingObject);
     }
     
+    if (childBox.style().styleType() == FIRST_LETTER && childBox.style().initialLetterDrop() > 0) {
+        const RenderStyle& style = firstLineStyle();
+        const FontMetrics& fontMetrics = style.fontMetrics();
+        if (fontMetrics.hasCapHeight()) {
+            LayoutUnit heightOfLine = lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
+            LayoutUnit beforeMarginBorderPadding = childBox.borderAndPaddingBefore() + childBox.marginBefore();
+            
+            // Make an adjustment to align with the cap height of a theoretical block line.
+            LayoutUnit adjustment = fontMetrics.ascent() + (heightOfLine - fontMetrics.height()) / 2 - fontMetrics.capHeight() - beforeMarginBorderPadding;
+            logicalTopOffset += adjustment;
+           
+            // For sunken and raised caps, we have to make some adjustments. Test if we're sunken or raised (dropHeightDelta will be
+            // positive for raised and negative for sunken).
+            int dropHeightDelta = childBox.style().initialLetterHeight() - childBox.style().initialLetterDrop();
+            
+            // If we're sunken, the float needs to shift down but lines still need to avoid it. In order to do that we increase the float's margin.
+            if (dropHeightDelta < 0) {
+                LayoutUnit marginTopIncrease = -dropHeightDelta * heightOfLine;
+                childBox.setMarginBefore(childBox.marginTop() + marginTopIncrease);
+            }
+            
+            // If we're raised, then we actually have to grow the height of the block, since the lines have to be pushed down as though we're placing
+            // empty lines beside the first letter.
+            if (dropHeightDelta > 0)
+                setLogicalHeight(logicalHeight() + dropHeightDelta * heightOfLine);
+        }
+    }
+    
     return LayoutPoint(floatLogicalLeft, logicalTopOffset);
 }
 
index fe5af17..b3b1278 100644 (file)
@@ -478,7 +478,7 @@ private:
     FloatingObject* insertFloatingObject(RenderBox&);
     void removeFloatingObject(RenderBox&);
     void removeFloatingObjectsBelow(FloatingObject*, int logicalOffset);
-    LayoutPoint computeLogicalLocationForFloat(const FloatingObject*, LayoutUnit logicalTopOffset) const;
+    LayoutPoint computeLogicalLocationForFloat(const FloatingObject*, LayoutUnit logicalTopOffset);
 
     // Called from lineWidth, to position the floats added in the last line.
     // Returns true if and only if it has positioned any floats.
index b77a85b..a99f6c9 100644 (file)
@@ -1490,8 +1490,10 @@ void RenderBlockFlow::checkFloatsInCleanLine(RootInlineBox* line, Vector<FloatWi
             encounteredNewFloat = true;
             return;
         }
-
-        if (floats[floatIndex].rect.size() != newSize) {
+    
+        // We have to reset the cap-height alignment done by the first-letter floats when initial-letter is set, so just always treat first-letter floats
+        // as dirty.
+        if (floats[floatIndex].rect.size() != newSize || (floatingBox->style().styleType() == FIRST_LETTER && floatingBox->style().initialLetterDrop() > 0)) {
             LayoutUnit floatTop = isHorizontalWritingMode() ? floats[floatIndex].rect.y() : floats[floatIndex].rect.x();
             LayoutUnit floatHeight = isHorizontalWritingMode() ? std::max(floats[floatIndex].rect.height(), newSize.height()) : std::max(floats[floatIndex].rect.width(), newSize.width());
             floatHeight = std::min(floatHeight, LayoutUnit::max() - floatTop);
index 9ec42d3..dc84ba1 100644 (file)
@@ -900,6 +900,20 @@ void RootInlineBox::ascentAndDescentForBox(InlineBox& box, GlyphOverflowAndFallb
         glyphOverflow->top = std::min(glyphOverflow->top, std::max(0, glyphOverflow->top - boxLineStyle.fontMetrics().ascent(baselineType())));
         glyphOverflow->bottom = std::min(glyphOverflow->bottom, std::max(0, glyphOverflow->bottom - boxLineStyle.fontMetrics().descent(baselineType())));
     }
+    
+    if (includeInitialLetterForBox(box)) {
+        // FIXME: Can't use glyph bounds in vertical writing mode because they are garbage.
+        bool canUseGlyphs = isHorizontal() && glyphOverflow && glyphOverflow->computeBounds;
+        int letterAscent = baselineType() == AlphabeticBaseline ? boxLineStyle.fontMetrics().capHeight() : (canUseGlyphs ? glyphOverflow->top : boxLineStyle.fontMetrics().ascent(baselineType()));
+        int letterDescent = canUseGlyphs ? glyphOverflow->bottom : (box.isRootInlineBox() ? 0 : boxLineStyle.fontMetrics().descent(baselineType()));
+        setAscentAndDescent(ascent, descent, letterAscent, letterDescent, ascentDescentSet);
+        affectsAscent = letterAscent - box.logicalTop() > 0;
+        affectsDescent = letterDescent + box.logicalTop() > 0;
+        if (canUseGlyphs) {
+            glyphOverflow->top = std::min(glyphOverflow->top, std::max(0, glyphOverflow->top - boxLineStyle.fontMetrics().ascent(baselineType())));
+            glyphOverflow->bottom = std::min(glyphOverflow->bottom, std::max(0, glyphOverflow->bottom - boxLineStyle.fontMetrics().descent(baselineType())));
+        }
+    }
 
     if (includeMarginForBox(box)) {
         LayoutUnit ascentWithMargin = boxLineStyle.fontMetrics().ascent(baselineType());
@@ -1024,6 +1038,18 @@ bool RootInlineBox::includeGlyphsForBox(InlineBox& box) const
     return isHorizontal() && (lineBoxContain & LineBoxContainGlyphs);
 }
 
+bool RootInlineBox::includeInitialLetterForBox(InlineBox& box) const
+{
+    if (box.renderer().isReplaced() || (box.renderer().isTextOrLineBreak() && !box.behavesLikeText()))
+        return false;
+    
+    if (!box.behavesLikeText() && box.isInlineFlowBox() && !toInlineFlowBox(&box)->hasTextChildren())
+        return false;
+
+    LineBoxContain lineBoxContain = renderer().style().lineBoxContain();
+    return (lineBoxContain & LineBoxContainInitialLetter);
+}
+
 bool RootInlineBox::includeMarginForBox(InlineBox& box) const
 {
     if (box.renderer().isReplaced() || (box.renderer().isTextOrLineBreak() && !box.behavesLikeText()))
@@ -1038,7 +1064,7 @@ bool RootInlineBox::fitsToGlyphs() const
 {
     // FIXME: We can't fit to glyphs yet for vertical text, since the bounds returned are garbage.
     LineBoxContain lineBoxContain = renderer().style().lineBoxContain();
-    return isHorizontal() && (lineBoxContain & LineBoxContainGlyphs);
+    return isHorizontal() && ((lineBoxContain & LineBoxContainGlyphs) || (lineBoxContain & LineBoxContainInitialLetter));
 }
 
 bool RootInlineBox::includesRootLineBoxFontOrLeading() const
index 37fe5cc..d97b535 100644 (file)
@@ -195,6 +195,7 @@ private:
     bool includeLeadingForBox(InlineBox&) const;
     bool includeFontForBox(InlineBox&) const;
     bool includeGlyphsForBox(InlineBox&) const;
+    bool includeInitialLetterForBox(InlineBox&) const;
     bool includeMarginForBox(InlineBox&) const;
 
     LayoutUnit lineSnapAdjustment(LayoutUnit delta = 0) const;
index 343125c..48e210d 100644 (file)
@@ -434,6 +434,7 @@ bool RenderStyle::changeRequiresLayout(const RenderStyle* other, unsigned& chang
             || rareNonInheritedData->marginBeforeCollapse != other->rareNonInheritedData->marginBeforeCollapse
             || rareNonInheritedData->marginAfterCollapse != other->rareNonInheritedData->marginAfterCollapse
             || rareNonInheritedData->lineClamp != other->rareNonInheritedData->lineClamp
+            || rareNonInheritedData->m_initialLetter != other->rareNonInheritedData->m_initialLetter
             || rareNonInheritedData->textOverflow != other->rareNonInheritedData->textOverflow)
             return true;
 
index b74bcc6..73537ef 100644 (file)
@@ -1082,6 +1082,10 @@ public:
 
     LineBoxContain lineBoxContain() const { return rareInheritedData->m_lineBoxContain; }
     const LineClampValue& lineClamp() const { return rareNonInheritedData->lineClamp; }
+    const IntSize& initialLetter() const { return rareNonInheritedData->m_initialLetter; }
+    int initialLetterDrop() const { return initialLetter().width(); }
+    int initialLetterHeight() const { return initialLetter().height(); }
+
 #if ENABLE(CSS_SCROLL_SNAP)
     ScrollSnapType scrollSnapType() const { return static_cast<ScrollSnapType>(rareNonInheritedData->m_scrollSnapType); }
     Vector<Length> scrollSnapOffsetsX() const { return rareNonInheritedData->m_scrollSnapPoints->offsetsX; }
@@ -1612,6 +1616,9 @@ public:
 
     void setLineBoxContain(LineBoxContain c) { SET_VAR(rareInheritedData, m_lineBoxContain, c); }
     void setLineClamp(LineClampValue c) { SET_VAR(rareNonInheritedData, lineClamp, c); }
+    
+    void setInitialLetter(const IntSize& size) { SET_VAR(rareNonInheritedData, m_initialLetter, size); }
+    
 #if ENABLE(CSS_SCROLL_SNAP)
     void setScrollSnapType(ScrollSnapType type) { SET_VAR(rareNonInheritedData, m_scrollSnapType, type); }
     void setScrollSnapOffsetsX(Vector<Length>& offsets) { SET_VAR(rareNonInheritedData.access()->m_scrollSnapPoints, offsetsX, offsets); }
@@ -1982,6 +1989,7 @@ public:
     static RegionFragment initialRegionFragment() { return AutoRegionFragment; }
 
     // Keep these at the end.
+    static IntSize initialInitialLetter() { return IntSize(); }
     static LineClampValue initialLineClamp() { return LineClampValue(); }
     static ETextSecurity initialTextSecurity() { return TSNONE; }
 #if ENABLE(IOS_TEXT_AUTOSIZING)
index ee84ae2..3a24066 100644 (file)
@@ -41,6 +41,7 @@ StyleRareNonInheritedData::StyleRareNonInheritedData()
     , m_perspectiveOriginX(RenderStyle::initialPerspectiveOriginX())
     , m_perspectiveOriginY(RenderStyle::initialPerspectiveOriginY())
     , lineClamp(RenderStyle::initialLineClamp())
+    , m_initialLetter(RenderStyle::initialInitialLetter())
     , m_deprecatedFlexibleBox(StyleDeprecatedFlexibleBoxData::create())
     , m_flexibleBox(StyleFlexibleBoxData::create())
     , m_marquee(StyleMarqueeData::create())
@@ -112,6 +113,7 @@ inline StyleRareNonInheritedData::StyleRareNonInheritedData(const StyleRareNonIn
     , m_perspectiveOriginX(o.m_perspectiveOriginX)
     , m_perspectiveOriginY(o.m_perspectiveOriginY)
     , lineClamp(o.lineClamp)
+    , m_initialLetter(o.m_initialLetter)
     , m_deprecatedFlexibleBox(o.m_deprecatedFlexibleBox)
     , m_flexibleBox(o.m_flexibleBox)
     , m_marquee(o.m_marquee)
@@ -205,6 +207,7 @@ bool StyleRareNonInheritedData::operator==(const StyleRareNonInheritedData& o) c
         && m_perspectiveOriginX == o.m_perspectiveOriginX
         && m_perspectiveOriginY == o.m_perspectiveOriginY
         && lineClamp == o.lineClamp
+        && m_initialLetter == o.m_initialLetter
 #if ENABLE(DASHBOARD_SUPPORT)
         && m_dashboardRegions == o.m_dashboardRegions
 #endif
index e536de4..f0254c0 100644 (file)
@@ -108,6 +108,9 @@ public:
     Length m_perspectiveOriginY;
 
     LineClampValue lineClamp; // An Apple extension.
+    
+    IntSize m_initialLetter;
+
 #if ENABLE(DASHBOARD_SUPPORT)
     Vector<StyleDashboardRegion> m_dashboardRegions;
 #endif