Diff
Modified: releases/WebKitGTK/webkit-2.18/Source/WebCore/CMakeLists.txt (220845 => 220846)
--- releases/WebKitGTK/webkit-2.18/Source/WebCore/CMakeLists.txt 2017-08-17 07:50:38 UTC (rev 220845)
+++ releases/WebKitGTK/webkit-2.18/Source/WebCore/CMakeLists.txt 2017-08-17 07:57:09 UTC (rev 220846)
@@ -2795,6 +2795,7 @@
style/InlineTextBoxStyle.cpp
style/RenderTreePosition.cpp
style/RenderTreeUpdater.cpp
+ style/RenderTreeUpdaterFirstLetter.cpp
style/StyleChange.cpp
style/StyleFontSizeFunctions.cpp
style/StyleInvalidator.cpp
Modified: releases/WebKitGTK/webkit-2.18/Source/WebCore/ChangeLog (220845 => 220846)
--- releases/WebKitGTK/webkit-2.18/Source/WebCore/ChangeLog 2017-08-17 07:50:38 UTC (rev 220845)
+++ releases/WebKitGTK/webkit-2.18/Source/WebCore/ChangeLog 2017-08-17 07:57:09 UTC (rev 220846)
@@ -1,3 +1,51 @@
+2017-08-16 Antti Koivisto <[email protected]>
+
+ Move first-letter renderer mutation code out of RenderBlock and into RenderTreeUpdater
+ https://bugs.webkit.org/show_bug.cgi?id=175627
+
+ Reviewed by Andreas Kling.
+
+ Render tree should not mutate itself. We already fixed this for first-letter, supporting code
+ can now move to RenderTreeUpdater too.
+
+ * CMakeLists.txt:
+ * WebCore.xcodeproj/project.pbxproj:
+ * rendering/RenderBlock.cpp:
+ (WebCore::styleForFirstLetter): Deleted.
+ (WebCore::isPunctuationForFirstLetter): Deleted.
+ (WebCore::shouldSkipForFirstLetter): Deleted.
+ (WebCore::RenderBlock::updateFirstLetterStyle): Deleted.
+ (WebCore::RenderBlock::createFirstLetterRenderer): Deleted.
+ (WebCore::RenderBlock::updateFirstLetter): Deleted.
+ * rendering/RenderBlock.h:
+ * rendering/RenderRubyRun.cpp:
+ (WebCore::RenderRubyRun::updateFirstLetter): Deleted.
+ * rendering/RenderRubyRun.h:
+ * rendering/RenderTable.cpp:
+ (WebCore::RenderTable::updateFirstLetter): Deleted.
+ * rendering/RenderTable.h:
+
+ Virtual overrides just disabled first letter for some RenderBlock subclasses. This is now achieved via
+ supportsFirstLetter test in the first letter updater.
+
+ * rendering/TextAutoSizing.cpp:
+ (WebCore::TextAutoSizingValue::adjustTextNodeSizes):
+ * rendering/svg/RenderSVGText.cpp:
+ (WebCore::RenderSVGText::updateFirstLetter): Deleted.
+ * rendering/svg/RenderSVGText.h:
+ * style/RenderTreeUpdater.cpp:
+ (WebCore::RenderTreeUpdater::popParent):
+ * style/RenderTreeUpdater.h:
+ * style/RenderTreeUpdaterFirstLetter.cpp: Added.
+ (WebCore::styleForFirstLetter):
+ (WebCore::isPunctuationForFirstLetter):
+ (WebCore::shouldSkipForFirstLetter):
+ (WebCore::updateFirstLetterStyle):
+ (WebCore::createFirstLetterRenderer):
+ (WebCore::supportsFirstLetter):
+ (WebCore::RenderTreeUpdater::FirstLetter::update):
+ * style/RenderTreeUpdaterFirstLetter.h: Added.
+
2017-08-15 Darin Adler <[email protected]>
REGRESSION(r220052): http/tests/appcache/deferred-events-delete-while-raising-timer.html is crashing.
Modified: releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/RenderBlock.cpp (220845 => 220846)
--- releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/RenderBlock.cpp 2017-08-17 07:50:38 UTC (rev 220845)
+++ releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/RenderBlock.cpp 2017-08-17 07:57:09 UTC (rev 220846)
@@ -3085,70 +3085,6 @@
return firstLineBlock;
}
-static RenderStyle styleForFirstLetter(const RenderElement& firstLetterBlock, const RenderObject& firstLetterContainer)
-{
- auto* containerFirstLetterStyle = firstLetterBlock.getCachedPseudoStyle(FIRST_LETTER, &firstLetterContainer.firstLineStyle());
- // FIXME: There appears to be some path where we have a first letter renderer without first letter style.
- ASSERT(containerFirstLetterStyle);
- auto firstLetterStyle = RenderStyle::clone(containerFirstLetterStyle ? *containerFirstLetterStyle : firstLetterContainer.firstLineStyle());
-
- // If we have an initial letter drop that is >= 1, then we need to force floating to be on.
- if (firstLetterStyle.initialLetterDrop() >= 1 && !firstLetterStyle.isFloating())
- firstLetterStyle.setFloating(firstLetterStyle.isLeftToRightDirection() ? LeftFloat : RightFloat);
-
- // We have to compute the correct font-size for the first-letter if it has an initial letter height set.
- auto* paragraph = firstLetterContainer.isRenderBlockFlow() ? &firstLetterContainer : firstLetterContainer.containingBlock();
- if (firstLetterStyle.initialLetterHeight() >= 1 && firstLetterStyle.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.
- firstLetterStyle.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.
- auto newFontDescription = firstLetterStyle.fontDescription();
- float capRatio = firstLetterStyle.fontMetrics().floatCapHeight() / firstLetterStyle.computedFontPixelSize();
- float startingFontSize = ((firstLetterStyle.initialLetterHeight() - 1) * lineHeight + paragraph->style().fontMetrics().capHeight()) / capRatio;
- newFontDescription.setSpecifiedSize(startingFontSize);
- newFontDescription.setComputedSize(startingFontSize);
- firstLetterStyle.setFontDescription(newFontDescription);
- firstLetterStyle.fontCascade().update(firstLetterStyle.fontCascade().fontSelector());
-
- int desiredCapHeight = (firstLetterStyle.initialLetterHeight() - 1) * lineHeight + paragraph->style().fontMetrics().capHeight();
- int actualCapHeight = firstLetterStyle.fontMetrics().capHeight();
- while (actualCapHeight > desiredCapHeight) {
- auto newFontDescription = firstLetterStyle.fontDescription();
- newFontDescription.setSpecifiedSize(newFontDescription.specifiedSize() - 1);
- newFontDescription.setComputedSize(newFontDescription.computedSize() -1);
- firstLetterStyle.setFontDescription(newFontDescription);
- firstLetterStyle.fontCascade().update(firstLetterStyle.fontCascade().fontSelector());
- actualCapHeight = firstLetterStyle.fontMetrics().capHeight();
- }
- }
-
- // Force inline display (except for floating first-letters).
- firstLetterStyle.setDisplay(firstLetterStyle.isFloating() ? BLOCK : INLINE);
- // CSS2 says first-letter can't be positioned.
- firstLetterStyle.setPosition(StaticPosition);
- return firstLetterStyle;
-}
-
-// CSS 2.1 http://www.w3.org/TR/CSS21/selector.html#first-letter
-// "Punctuation (i.e, characters defined in Unicode [UNICODE] in the "open" (Ps), "close" (Pe),
-// "initial" (Pi). "final" (Pf) and "other" (Po) punctuation classes), that precedes or follows the first letter should be included"
-static inline bool isPunctuationForFirstLetter(UChar c)
-{
- return U_GET_GC_MASK(c) & (U_GC_PS_MASK | U_GC_PE_MASK | U_GC_PI_MASK | U_GC_PF_MASK | U_GC_PO_MASK);
-}
-
-static inline bool shouldSkipForFirstLetter(UChar c)
-{
- return isSpaceOrNewline(c) || c == noBreakSpace || isPunctuationForFirstLetter(c);
-}
-
static inline RenderBlock* findFirstLetterBlock(RenderBlock* start)
{
RenderBlock* firstLetterBlock = start;
@@ -3169,117 +3105,6 @@
return nullptr;
}
-void RenderBlock::updateFirstLetterStyle(RenderElement* firstLetterBlock, RenderObject* currentChild)
-{
- RenderElement* firstLetter = currentChild->parent();
- RenderElement* firstLetterContainer = firstLetter->parent();
- auto pseudoStyle = styleForFirstLetter(*firstLetterBlock, *firstLetterContainer);
- ASSERT(firstLetter->isFloating() || firstLetter->isInline());
-
- if (Style::determineChange(firstLetter->style(), pseudoStyle) == Style::Detach) {
- // The first-letter renderer needs to be replaced. Create a new renderer of the right type.
- RenderBoxModelObject* newFirstLetter;
- if (pseudoStyle.display() == INLINE)
- newFirstLetter = new RenderInline(document(), WTFMove(pseudoStyle));
- else
- newFirstLetter = new RenderBlockFlow(document(), WTFMove(pseudoStyle));
- newFirstLetter->initializeStyle();
-
- // Move the first letter into the new renderer.
- LayoutStateDisabler layoutStateDisabler(view());
- while (RenderObject* child = firstLetter->firstChild()) {
- if (is<RenderText>(*child))
- downcast<RenderText>(*child).removeAndDestroyTextBoxes();
- firstLetter->removeChild(*child);
- newFirstLetter->addChild(child, nullptr);
- }
-
- RenderObject* nextSibling = firstLetter->nextSibling();
- if (RenderTextFragment* remainingText = downcast<RenderBoxModelObject>(*firstLetter).firstLetterRemainingText()) {
- ASSERT(remainingText->isAnonymous() || remainingText->textNode()->renderer() == remainingText);
- // Replace the old renderer with the new one.
- remainingText->setFirstLetter(*newFirstLetter);
- newFirstLetter->setFirstLetterRemainingText(remainingText);
- }
- // To prevent removal of single anonymous block in RenderBlock::removeChild and causing
- // |nextSibling| to go stale, we remove the old first letter using removeChildNode first.
- firstLetterContainer->removeChildInternal(*firstLetter, NotifyChildren);
- firstLetter->destroy();
- firstLetter = newFirstLetter;
- firstLetterContainer->addChild(firstLetter, nextSibling);
- } else
- firstLetter->setStyle(WTFMove(pseudoStyle));
-}
-
-void RenderBlock::createFirstLetterRenderer(RenderElement* firstLetterBlock, RenderText* currentTextChild)
-{
- RenderElement* firstLetterContainer = currentTextChild->parent();
- auto pseudoStyle = styleForFirstLetter(*firstLetterBlock, *firstLetterContainer);
- RenderBoxModelObject* firstLetter = nullptr;
- if (pseudoStyle.display() == INLINE)
- firstLetter = new RenderInline(document(), WTFMove(pseudoStyle));
- else
- firstLetter = new RenderBlockFlow(document(), WTFMove(pseudoStyle));
- firstLetter->initializeStyle();
- firstLetterContainer->addChild(firstLetter, currentTextChild);
-
- // The original string is going to be either a generated content string or a DOM node's
- // string. We want the original string before it got transformed in case first-letter has
- // no text-transform or a different text-transform applied to it.
- String oldText = currentTextChild->originalText();
- ASSERT(!oldText.isNull());
-
- if (!oldText.isEmpty()) {
- unsigned length = 0;
-
- // Account for leading spaces and punctuation.
- while (length < oldText.length() && shouldSkipForFirstLetter(oldText[length]))
- length++;
-
- // Account for first grapheme cluster.
- length += numCharactersInGraphemeClusters(StringView(oldText).substring(length), 1);
-
- // Keep looking for whitespace and allowed punctuation, but avoid
- // accumulating just whitespace into the :first-letter.
- for (unsigned scanLength = length; scanLength < oldText.length(); ++scanLength) {
- UChar c = oldText[scanLength];
-
- if (!shouldSkipForFirstLetter(c))
- break;
-
- if (isPunctuationForFirstLetter(c))
- length = scanLength + 1;
- }
-
- // Construct a text fragment for the text after the first letter.
- // This text fragment might be empty.
- RenderTextFragment* remainingText;
- if (currentTextChild->textNode())
- remainingText = new RenderTextFragment(*currentTextChild->textNode(), oldText, length, oldText.length() - length);
- else
- remainingText = new RenderTextFragment(document(), oldText, length, oldText.length() - length);
-
- if (remainingText->textNode())
- remainingText->textNode()->setRenderer(remainingText);
-
- firstLetterContainer->addChild(remainingText, currentTextChild);
- firstLetterContainer->removeChild(*currentTextChild);
- remainingText->setFirstLetter(*firstLetter);
- firstLetter->setFirstLetterRemainingText(remainingText);
-
- // construct text fragment for the first letter
- RenderTextFragment* letter;
- if (remainingText->textNode())
- letter = new RenderTextFragment(*remainingText->textNode(), oldText, 0, length);
- else
- letter = new RenderTextFragment(document(), oldText, 0, length);
-
- firstLetter->addChild(letter);
-
- currentTextChild->destroy();
- }
-}
-
void RenderBlock::getFirstLetter(RenderObject*& firstLetter, RenderElement*& firstLetterContainer, RenderObject* skipObject)
{
firstLetter = nullptr;
@@ -3335,32 +3160,6 @@
firstLetterContainer = nullptr;
}
-void RenderBlock::updateFirstLetter()
-{
- ASSERT_WITH_SECURITY_IMPLICATION(!view().layoutState());
-
- RenderObject* firstLetterObj;
- RenderElement* firstLetterContainer;
- // FIXME: The first letter might be composed of a variety of code units, and therefore might
- // be contained within multiple RenderElements.
- getFirstLetter(firstLetterObj, firstLetterContainer);
-
- if (!firstLetterObj || !firstLetterContainer)
- return;
-
- // If the child already has style, then it has already been created, so we just want
- // to update it.
- if (firstLetterObj->parent()->style().styleType() == FIRST_LETTER) {
- updateFirstLetterStyle(firstLetterContainer, firstLetterObj);
- return;
- }
-
- if (!is<RenderText>(*firstLetterObj))
- return;
-
- createFirstLetterRenderer(firstLetterContainer, downcast<RenderText>(firstLetterObj));
-}
-
RenderFlowThread* RenderBlock::cachedFlowThreadContainingBlock() const
{
RenderBlockRareData* rareData = getBlockRareData(*this);
Modified: releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/RenderBlock.h (220845 => 220846)
--- releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/RenderBlock.h 2017-08-17 07:50:38 UTC (rev 220845)
+++ releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/RenderBlock.h 2017-08-17 07:57:09 UTC (rev 220846)
@@ -263,7 +263,6 @@
LayoutUnit collapsedMarginBeforeForChild(const RenderBox& child) const;
LayoutUnit collapsedMarginAfterForChild(const RenderBox& child) const;
- virtual void updateFirstLetter();
void getFirstLetter(RenderObject*& firstLetter, RenderElement*& firstLetterContainer, RenderObject* skipObject = nullptr);
virtual void scrollbarsChanged(bool /*horizontalScrollbarChanged*/, bool /*verticalScrollbarChanged*/) { }
@@ -454,9 +453,6 @@
bool isSelfCollapsingBlock() const override;
virtual bool childrenPreventSelfCollapsing() const;
- void createFirstLetterRenderer(RenderElement* firstLetterBlock, RenderText* currentTextChild);
- void updateFirstLetterStyle(RenderElement* firstLetterBlock, RenderObject* firstLetterContainer);
-
Node* nodeForHitTest() const;
// FIXME-BLOCKFLOW: Remove virtualizaion when all callers have moved to RenderBlockFlow
Modified: releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/RenderRubyRun.cpp (220845 => 220846)
--- releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/RenderRubyRun.cpp 2017-08-17 07:50:38 UTC (rev 220845)
+++ releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/RenderRubyRun.cpp 2017-08-17 07:57:09 UTC (rev 220846)
@@ -101,10 +101,6 @@
return 0;
}
-void RenderRubyRun::updateFirstLetter()
-{
-}
-
bool RenderRubyRun::isChildAllowed(const RenderObject& child, const RenderStyle&) const
{
return child.isInline() || child.isRubyText();
Modified: releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/RenderRubyRun.h (220845 => 220846)
--- releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/RenderRubyRun.h 2017-08-17 07:50:38 UTC (rev 220845)
+++ releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/RenderRubyRun.h 2017-08-17 07:57:09 UTC (rev 220846)
@@ -60,7 +60,6 @@
void removeChild(RenderObject&) override;
RenderBlock* firstLineBlock() const override;
- void updateFirstLetter() override;
void getOverhang(bool firstLine, RenderObject* startRenderer, RenderObject* endRenderer, float& startOverhang, float& endOverhang) const;
Modified: releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/RenderTable.cpp (220845 => 220846)
--- releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/RenderTable.cpp 2017-08-17 07:50:38 UTC (rev 220845)
+++ releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/RenderTable.cpp 2017-08-17 07:57:09 UTC (rev 220846)
@@ -1485,10 +1485,6 @@
return nullptr;
}
-void RenderTable::updateFirstLetter()
-{
-}
-
int RenderTable::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
{
return valueOrCompute(firstLineBaseline(), [&] {
Modified: releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/RenderTable.h (220845 => 220846)
--- releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/RenderTable.h 2017-08-17 07:50:38 UTC (rev 220845)
+++ releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/RenderTable.h 2017-08-17 07:57:09 UTC (rev 220846)
@@ -302,7 +302,6 @@
void invalidateCachedColumnOffsets();
RenderBlock* firstLineBlock() const final;
- void updateFirstLetter() final;
void updateLogicalWidth() final;
Modified: releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/TextAutoSizing.cpp (220845 => 220846)
--- releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/TextAutoSizing.cpp 2017-08-17 07:50:38 UTC (rev 220845)
+++ releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/TextAutoSizing.cpp 2017-08-17 07:57:09 UTC (rev 220846)
@@ -36,6 +36,7 @@
#include "RenderListMarker.h"
#include "RenderText.h"
#include "RenderTextFragment.h"
+#include "RenderTreeUpdaterFirstLetter.h"
#include "StyleResolver.h"
namespace WebCore {
@@ -157,7 +158,6 @@
parentRenderer->setStyle(WTFMove(newParentStyle));
}
- // FIXME: All render tree mutations should be done via RenderTreeUpdater.
for (auto& node : m_autoSizedNodes) {
auto& textRenderer = *node->renderer();
if (!is<RenderTextFragment>(textRenderer))
@@ -165,7 +165,8 @@
auto* block = downcast<RenderTextFragment>(textRenderer).blockForAccompanyingFirstLetter();
if (!block)
continue;
- block->updateFirstLetter();
+ // FIXME: All render tree mutations should be done by RenderTreeUpdater commit.
+ RenderTreeUpdater::FirstLetter::update(*block);
}
return stillHasNodes;
Modified: releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/svg/RenderSVGText.cpp (220845 => 220846)
--- releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/svg/RenderSVGText.cpp 2017-08-17 07:50:38 UTC (rev 220845)
+++ releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/svg/RenderSVGText.cpp 2017-08-17 07:57:09 UTC (rev 220846)
@@ -542,10 +542,4 @@
return 0;
}
-// Fix for <rdar://problem/8048875>. We should not render :first-letter CSS Style
-// in a SVG text element context.
-void RenderSVGText::updateFirstLetter()
-{
}
-
-}
Modified: releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/svg/RenderSVGText.h (220845 => 220846)
--- releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/svg/RenderSVGText.h 2017-08-17 07:50:38 UTC (rev 220845)
+++ releases/WebKitGTK/webkit-2.18/Source/WebCore/rendering/svg/RenderSVGText.h 2017-08-17 07:57:09 UTC (rev 220846)
@@ -91,7 +91,6 @@
std::unique_ptr<RootInlineBox> createRootInlineBox() override;
RenderBlock* firstLineBlock() const override;
- void updateFirstLetter() override;
bool shouldHandleSubtreeMutations() const;
Modified: releases/WebKitGTK/webkit-2.18/Source/WebCore/style/RenderTreeUpdater.cpp (220845 => 220846)
--- releases/WebKitGTK/webkit-2.18/Source/WebCore/style/RenderTreeUpdater.cpp 2017-08-17 07:50:38 UTC (rev 220845)
+++ releases/WebKitGTK/webkit-2.18/Source/WebCore/style/RenderTreeUpdater.cpp 2017-08-17 07:57:09 UTC (rev 220846)
@@ -41,6 +41,7 @@
#include "RenderFullScreen.h"
#include "RenderNamedFlowThread.h"
#include "RenderQuote.h"
+#include "RenderTreeUpdaterFirstLetter.h"
#include "StyleResolver.h"
#include "StyleTreeResolver.h"
#include <wtf/SystemTracing.h>
@@ -234,7 +235,7 @@
auto* renderer = parent.element->renderer();
if (is<RenderBlock>(renderer))
- downcast<RenderBlock>(*renderer).updateFirstLetter();
+ FirstLetter::update(downcast<RenderBlock>(*renderer));
if (parent.element->hasCustomStyleResolveCallbacks() && parent.styleChange == Style::Detach && renderer)
parent.element->didAttachRenderers();
Modified: releases/WebKitGTK/webkit-2.18/Source/WebCore/style/RenderTreeUpdater.h (220845 => 220846)
--- releases/WebKitGTK/webkit-2.18/Source/WebCore/style/RenderTreeUpdater.h 2017-08-17 07:50:38 UTC (rev 220845)
+++ releases/WebKitGTK/webkit-2.18/Source/WebCore/style/RenderTreeUpdater.h 2017-08-17 07:57:09 UTC (rev 220846)
@@ -51,6 +51,8 @@
static void tearDownRenderers(Element&, TeardownType = TeardownType::Normal);
static void tearDownRenderer(Text&);
+ class FirstLetter;
+
private:
void updateRenderTree(ContainerNode& root);
void updateTextRenderer(Text&, const Style::TextUpdate*);
Added: releases/WebKitGTK/webkit-2.18/Source/WebCore/style/RenderTreeUpdaterFirstLetter.cpp (0 => 220846)
--- releases/WebKitGTK/webkit-2.18/Source/WebCore/style/RenderTreeUpdaterFirstLetter.cpp (rev 0)
+++ releases/WebKitGTK/webkit-2.18/Source/WebCore/style/RenderTreeUpdaterFirstLetter.cpp 2017-08-17 07:57:09 UTC (rev 220846)
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 1999 Lars Knoll ([email protected])
+ * (C) 1999 Antti Koivisto ([email protected])
+ * (C) 2007 David Smith ([email protected])
+ * Copyright (C) 2003-2011, 2017 Apple Inc. All rights reserved.
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "RenderTreeUpdaterFirstLetter.h"
+
+#include "FontCascade.h"
+#include "RenderBlock.h"
+#include "RenderInline.h"
+#include "RenderRubyRun.h"
+#include "RenderSVGText.h"
+#include "RenderStyle.h"
+#include "RenderTable.h"
+#include "RenderTextFragment.h"
+
+namespace WebCore {
+
+static RenderStyle styleForFirstLetter(const RenderElement& firstLetterBlock, const RenderObject& firstLetterContainer)
+{
+ auto* containerFirstLetterStyle = firstLetterBlock.getCachedPseudoStyle(FIRST_LETTER, &firstLetterContainer.firstLineStyle());
+ // FIXME: There appears to be some path where we have a first letter renderer without first letter style.
+ ASSERT(containerFirstLetterStyle);
+ auto firstLetterStyle = RenderStyle::clone(containerFirstLetterStyle ? *containerFirstLetterStyle : firstLetterContainer.firstLineStyle());
+
+ // If we have an initial letter drop that is >= 1, then we need to force floating to be on.
+ if (firstLetterStyle.initialLetterDrop() >= 1 && !firstLetterStyle.isFloating())
+ firstLetterStyle.setFloating(firstLetterStyle.isLeftToRightDirection() ? LeftFloat : RightFloat);
+
+ // We have to compute the correct font-size for the first-letter if it has an initial letter height set.
+ auto* paragraph = firstLetterContainer.isRenderBlockFlow() ? &firstLetterContainer : firstLetterContainer.containingBlock();
+ if (firstLetterStyle.initialLetterHeight() >= 1 && firstLetterStyle.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.
+ firstLetterStyle.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.
+ auto newFontDescription = firstLetterStyle.fontDescription();
+ float capRatio = firstLetterStyle.fontMetrics().floatCapHeight() / firstLetterStyle.computedFontPixelSize();
+ float startingFontSize = ((firstLetterStyle.initialLetterHeight() - 1) * lineHeight + paragraph->style().fontMetrics().capHeight()) / capRatio;
+ newFontDescription.setSpecifiedSize(startingFontSize);
+ newFontDescription.setComputedSize(startingFontSize);
+ firstLetterStyle.setFontDescription(newFontDescription);
+ firstLetterStyle.fontCascade().update(firstLetterStyle.fontCascade().fontSelector());
+
+ int desiredCapHeight = (firstLetterStyle.initialLetterHeight() - 1) * lineHeight + paragraph->style().fontMetrics().capHeight();
+ int actualCapHeight = firstLetterStyle.fontMetrics().capHeight();
+ while (actualCapHeight > desiredCapHeight) {
+ auto newFontDescription = firstLetterStyle.fontDescription();
+ newFontDescription.setSpecifiedSize(newFontDescription.specifiedSize() - 1);
+ newFontDescription.setComputedSize(newFontDescription.computedSize() -1);
+ firstLetterStyle.setFontDescription(newFontDescription);
+ firstLetterStyle.fontCascade().update(firstLetterStyle.fontCascade().fontSelector());
+ actualCapHeight = firstLetterStyle.fontMetrics().capHeight();
+ }
+ }
+
+ // Force inline display (except for floating first-letters).
+ firstLetterStyle.setDisplay(firstLetterStyle.isFloating() ? BLOCK : INLINE);
+ // CSS2 says first-letter can't be positioned.
+ firstLetterStyle.setPosition(StaticPosition);
+ return firstLetterStyle;
+}
+
+// CSS 2.1 http://www.w3.org/TR/CSS21/selector.html#first-letter
+// "Punctuation (i.e, characters defined in Unicode [UNICODE] in the "open" (Ps), "close" (Pe),
+// "initial" (Pi). "final" (Pf) and "other" (Po) punctuation classes), that precedes or follows the first letter should be included"
+static inline bool isPunctuationForFirstLetter(UChar c)
+{
+ return U_GET_GC_MASK(c) & (U_GC_PS_MASK | U_GC_PE_MASK | U_GC_PI_MASK | U_GC_PF_MASK | U_GC_PO_MASK);
+}
+
+static inline bool shouldSkipForFirstLetter(UChar c)
+{
+ return isSpaceOrNewline(c) || c == noBreakSpace || isPunctuationForFirstLetter(c);
+}
+
+static void updateFirstLetterStyle(RenderElement& firstLetterBlock, RenderObject& currentChild)
+{
+ RenderElement* firstLetter = currentChild.parent();
+ RenderElement* firstLetterContainer = firstLetter->parent();
+ auto pseudoStyle = styleForFirstLetter(firstLetterBlock, *firstLetterContainer);
+ ASSERT(firstLetter->isFloating() || firstLetter->isInline());
+
+ if (Style::determineChange(firstLetter->style(), pseudoStyle) == Style::Detach) {
+ // The first-letter renderer needs to be replaced. Create a new renderer of the right type.
+ RenderBoxModelObject* newFirstLetter;
+ if (pseudoStyle.display() == INLINE)
+ newFirstLetter = new RenderInline(firstLetterBlock.document(), WTFMove(pseudoStyle));
+ else
+ newFirstLetter = new RenderBlockFlow(firstLetterBlock.document(), WTFMove(pseudoStyle));
+ newFirstLetter->initializeStyle();
+
+ // Move the first letter into the new renderer.
+ LayoutStateDisabler layoutStateDisabler(firstLetterBlock.view());
+ while (RenderObject* child = firstLetter->firstChild()) {
+ if (is<RenderText>(*child))
+ downcast<RenderText>(*child).removeAndDestroyTextBoxes();
+ firstLetter->removeChild(*child);
+ newFirstLetter->addChild(child, nullptr);
+ }
+
+ RenderObject* nextSibling = firstLetter->nextSibling();
+ if (RenderTextFragment* remainingText = downcast<RenderBoxModelObject>(*firstLetter).firstLetterRemainingText()) {
+ ASSERT(remainingText->isAnonymous() || remainingText->textNode()->renderer() == remainingText);
+ // Replace the old renderer with the new one.
+ remainingText->setFirstLetter(*newFirstLetter);
+ newFirstLetter->setFirstLetterRemainingText(remainingText);
+ }
+ // To prevent removal of single anonymous block in RenderBlock::removeChild and causing
+ // |nextSibling| to go stale, we remove the old first letter using removeChildNode first.
+ firstLetterContainer->removeChildInternal(*firstLetter, RenderElement::NotifyChildren);
+ firstLetter->destroy();
+ firstLetter = newFirstLetter;
+ firstLetterContainer->addChild(firstLetter, nextSibling);
+ } else
+ firstLetter->setStyle(WTFMove(pseudoStyle));
+}
+
+static void createFirstLetterRenderer(RenderElement& firstLetterBlock, RenderText& currentTextChild)
+{
+ RenderElement* firstLetterContainer = currentTextChild.parent();
+ auto pseudoStyle = styleForFirstLetter(firstLetterBlock, *firstLetterContainer);
+ RenderBoxModelObject* firstLetter = nullptr;
+ if (pseudoStyle.display() == INLINE)
+ firstLetter = new RenderInline(firstLetterBlock.document(), WTFMove(pseudoStyle));
+ else
+ firstLetter = new RenderBlockFlow(firstLetterBlock.document(), WTFMove(pseudoStyle));
+ firstLetter->initializeStyle();
+ firstLetterContainer->addChild(firstLetter, ¤tTextChild);
+
+ // The original string is going to be either a generated content string or a DOM node's
+ // string. We want the original string before it got transformed in case first-letter has
+ // no text-transform or a different text-transform applied to it.
+ String oldText = currentTextChild.originalText();
+ ASSERT(!oldText.isNull());
+
+ if (!oldText.isEmpty()) {
+ unsigned length = 0;
+
+ // Account for leading spaces and punctuation.
+ while (length < oldText.length() && shouldSkipForFirstLetter(oldText[length]))
+ length++;
+
+ // Account for first grapheme cluster.
+ length += numCharactersInGraphemeClusters(StringView(oldText).substring(length), 1);
+
+ // Keep looking for whitespace and allowed punctuation, but avoid
+ // accumulating just whitespace into the :first-letter.
+ for (unsigned scanLength = length; scanLength < oldText.length(); ++scanLength) {
+ UChar c = oldText[scanLength];
+
+ if (!shouldSkipForFirstLetter(c))
+ break;
+
+ if (isPunctuationForFirstLetter(c))
+ length = scanLength + 1;
+ }
+
+ // Construct a text fragment for the text after the first letter.
+ // This text fragment might be empty.
+ RenderTextFragment* remainingText;
+ if (currentTextChild.textNode())
+ remainingText = new RenderTextFragment(*currentTextChild.textNode(), oldText, length, oldText.length() - length);
+ else
+ remainingText = new RenderTextFragment(firstLetterBlock.document(), oldText, length, oldText.length() - length);
+
+ if (remainingText->textNode())
+ remainingText->textNode()->setRenderer(remainingText);
+
+ firstLetterContainer->addChild(remainingText, ¤tTextChild);
+ firstLetterContainer->removeChild(currentTextChild);
+ remainingText->setFirstLetter(*firstLetter);
+ firstLetter->setFirstLetterRemainingText(remainingText);
+
+ // construct text fragment for the first letter
+ RenderTextFragment* letter;
+ if (remainingText->textNode())
+ letter = new RenderTextFragment(*remainingText->textNode(), oldText, 0, length);
+ else
+ letter = new RenderTextFragment(firstLetterBlock.document(), oldText, 0, length);
+
+ firstLetter->addChild(letter);
+
+ currentTextChild.destroy();
+ }
+}
+
+static bool supportsFirstLetter(RenderBlock& block)
+{
+ if (is<RenderTable>(block))
+ return false;
+ if (is<RenderSVGText>(block))
+ return false;
+ if (is<RenderRubyRun>(block))
+ return false;
+ return true;
+}
+
+void RenderTreeUpdater::FirstLetter::update(RenderBlock& block)
+{
+ ASSERT_WITH_SECURITY_IMPLICATION(!block.view().layoutState());
+
+ if (!supportsFirstLetter(block))
+ return;
+
+ RenderObject* firstLetterObj;
+ RenderElement* firstLetterContainer;
+ // FIXME: The first letter might be composed of a variety of code units, and therefore might
+ // be contained within multiple RenderElements.
+ block.getFirstLetter(firstLetterObj, firstLetterContainer);
+
+ if (!firstLetterObj || !firstLetterContainer)
+ return;
+
+ // If the child already has style, then it has already been created, so we just want
+ // to update it.
+ if (firstLetterObj->parent()->style().styleType() == FIRST_LETTER) {
+ updateFirstLetterStyle(*firstLetterContainer, *firstLetterObj);
+ return;
+ }
+
+ if (!is<RenderText>(*firstLetterObj))
+ return;
+
+ createFirstLetterRenderer(*firstLetterContainer, downcast<RenderText>(*firstLetterObj));
+}
+
+};
Added: releases/WebKitGTK/webkit-2.18/Source/WebCore/style/RenderTreeUpdaterFirstLetter.h (0 => 220846)
--- releases/WebKitGTK/webkit-2.18/Source/WebCore/style/RenderTreeUpdaterFirstLetter.h (rev 0)
+++ releases/WebKitGTK/webkit-2.18/Source/WebCore/style/RenderTreeUpdaterFirstLetter.h 2017-08-17 07:57:09 UTC (rev 220846)
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "RenderTreeUpdater.h"
+
+namespace WebCore {
+
+class RenderBlock;
+
+class RenderTreeUpdater::FirstLetter {
+public:
+ static void update(RenderBlock&);
+};
+
+}