[CSS Parser] Unprefix -webkit-writing-mode
[WebKit-https.git] / Source / WebCore / rendering / RenderLineBreak.cpp
index b4e8927..9d77038 100644 (file)
 
 #include "Document.h"
 #include "HTMLElement.h"
+#include "HTMLWBRElement.h"
+#include "InlineElementBox.h"
+#include "LogicalSelectionOffsetCaches.h"
 #include "RenderBlock.h"
+#include "RenderView.h"
 #include "RootInlineBox.h"
+#include "SimpleLineLayoutFunctions.h"
 #include "VisiblePosition.h"
 
+#if PLATFORM(IOS)
+#include "SelectionRect.h"
+#endif
+
 namespace WebCore {
 
 static const int invalidLineHeight = -1;
 
-RenderLineBreak::RenderLineBreak(HTMLElement& element)
-    : RenderBoxModelObject(&element, 0)
+static const SimpleLineLayout::Layout* simpleLineLayout(const RenderLineBreak& renderer)
+{
+    if (!is<RenderBlockFlow>(*renderer.parent()))
+        return nullptr;
+    return downcast<RenderBlockFlow>(*renderer.parent()).simpleLineLayout();
+}
+
+static void ensureLineBoxes(const RenderLineBreak& renderer)
+{
+    if (!is<RenderBlockFlow>(*renderer.parent()))
+        return;
+    downcast<RenderBlockFlow>(*renderer.parent()).ensureLineBoxes();
+}
+
+RenderLineBreak::RenderLineBreak(HTMLElement& element, RenderStyle&& style)
+    : RenderBoxModelObject(element, WTFMove(style), 0)
     , m_inlineBoxWrapper(nullptr)
     , m_cachedLineHeight(invalidLineHeight)
-    , m_isWBR(element.hasTagName(HTMLNames::wbrTag))
+    , m_isWBR(is<HTMLWBRElement>(element))
 {
     setIsLineBreak();
 }
 
 RenderLineBreak::~RenderLineBreak()
 {
-    if (m_inlineBoxWrapper)
-        m_inlineBoxWrapper->destroy(renderArena());
+    delete m_inlineBoxWrapper;
 }
 
 LayoutUnit RenderLineBreak::lineHeight(bool firstLine, LineDirectionMode /*direction*/, LinePositionMode /*linePositionMode*/) const
 {
-    if (firstLine && document().styleSheetCollection().usesFirstLineRules()) {
-        const RenderStyle& firstLineStyle = *this->firstLineStyle();
-        if (&firstLineStyle != style())
-            return firstLineStyle.computedLineHeight(&view());
+    if (firstLine && view().usesFirstLineRules()) {
+        const RenderStyle& firstLineStyle = this->firstLineStyle();
+        if (&firstLineStyle != &style())
+            return firstLineStyle.computedLineHeight();
     }
 
     if (m_cachedLineHeight == invalidLineHeight)
-        m_cachedLineHeight = style()->computedLineHeight(&view());
+        m_cachedLineHeight = style().computedLineHeight();
     
     return m_cachedLineHeight;
 }
 
 int RenderLineBreak::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
 {
-    const RenderStyle& style = firstLine ? *firstLineStyle() : *this->style();
+    const RenderStyle& style = firstLine ? firstLineStyle() : this->style();
     const FontMetrics& fontMetrics = style.fontMetrics();
     return fontMetrics.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - fontMetrics.height()) / 2;
 }
 
-InlineBox* RenderLineBreak::createInlineBox()
+std::unique_ptr<InlineElementBox> RenderLineBreak::createInlineBox()
 {
-    return new (renderArena()) InlineBox(*this);
+    return std::make_unique<InlineElementBox>(*this);
 }
 
-void RenderLineBreak::setInlineBoxWrapper(InlineBox* inlineBox)
+void RenderLineBreak::setInlineBoxWrapper(InlineElementBox* inlineBox)
 {
     ASSERT(!inlineBox || !m_inlineBoxWrapper);
     m_inlineBoxWrapper = inlineBox;
 }
 
-void RenderLineBreak::replaceInlineBoxWrapper(InlineBox* inlineBox)
+void RenderLineBreak::replaceInlineBoxWrapper(InlineElementBox& inlineBox)
 {
     deleteInlineBoxWrapper();
-    setInlineBoxWrapper(inlineBox);
+    setInlineBoxWrapper(&inlineBox);
 }
 
 void RenderLineBreak::deleteInlineBoxWrapper()
@@ -90,8 +112,8 @@ void RenderLineBreak::deleteInlineBoxWrapper()
     if (!m_inlineBoxWrapper)
         return;
     if (!documentBeingDestroyed())
-        m_inlineBoxWrapper->remove();
-    m_inlineBoxWrapper->destroy(renderArena());
+        m_inlineBoxWrapper->removeFromParent();
+    delete m_inlineBoxWrapper;
     m_inlineBoxWrapper = nullptr;
 }
 
@@ -100,13 +122,19 @@ void RenderLineBreak::dirtyLineBoxes(bool fullLayout)
     if (!m_inlineBoxWrapper)
         return;
     if (fullLayout) {
-        m_inlineBoxWrapper->destroy(renderArena());
+        delete m_inlineBoxWrapper;
         m_inlineBoxWrapper = nullptr;
         return;
     }
     m_inlineBoxWrapper->dirtyLineBoxes();
 }
 
+void RenderLineBreak::deleteLineBoxesBeforeSimpleLineLayout()
+{
+    delete m_inlineBoxWrapper;
+    m_inlineBoxWrapper = nullptr;
+}
+
 int RenderLineBreak::caretMinOffset() const
 {
     return 0;
@@ -122,40 +150,45 @@ bool RenderLineBreak::canBeSelectionLeaf() const
     return true;
 }
 
-VisiblePosition RenderLineBreak::positionForPoint(const LayoutPoint&)
+VisiblePosition RenderLineBreak::positionForPoint(const LayoutPoint&, const RenderRegion*)
 {
+    ensureLineBoxes(*this);
     return createVisiblePosition(0, DOWNSTREAM);
 }
 
 void RenderLineBreak::setSelectionState(SelectionState state)
 {
+    if (state != SelectionNone)
+        ensureLineBoxes(*this);
     RenderBoxModelObject::setSelectionState(state);
     if (!m_inlineBoxWrapper)
         return;
     m_inlineBoxWrapper->root().setHasSelectedChildren(state != SelectionNone);
 }
 
-LayoutRect RenderLineBreak::localCaretRect(InlineBox* inlineBox, int caretOffset, LayoutUnit* extraWidthToEndOfLine)
+LayoutRect RenderLineBreak::localCaretRect(InlineBox* inlineBox, unsigned caretOffset, LayoutUnit* extraWidthToEndOfLine)
 {
     ASSERT_UNUSED(caretOffset, !caretOffset);
     ASSERT_UNUSED(inlineBox, inlineBox == m_inlineBoxWrapper);
     if (!inlineBox)
         return LayoutRect();
 
-    static const unsigned caretWidth = 1;
     const RootInlineBox& rootBox = inlineBox->root();
     return rootBox.computeCaretRect(inlineBox->logicalLeft(), caretWidth, extraWidthToEndOfLine);
 }
 
 IntRect RenderLineBreak::linesBoundingBox() const
 {
+    if (auto* layout = simpleLineLayout(*this))
+        return SimpleLineLayout::computeBoundingBox(*this, *layout);
+
     if (!m_inlineBoxWrapper)
         return IntRect();
 
     float logicalLeftSide = m_inlineBoxWrapper->logicalLeft();
     float logicalRightSide = m_inlineBoxWrapper->logicalRight();
 
-    bool isHorizontal = style()->isHorizontalWritingMode();
+    bool isHorizontal = style().isHorizontalWritingMode();
 
     float x = isHorizontal ? logicalLeftSide : m_inlineBoxWrapper->x();
     float y = isHorizontal ? m_inlineBoxWrapper->y() : logicalLeftSide;
@@ -166,6 +199,11 @@ IntRect RenderLineBreak::linesBoundingBox() const
 
 void RenderLineBreak::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
 {
+    if (auto* layout = simpleLineLayout(*this)) {
+        rects.appendVector(SimpleLineLayout::collectAbsoluteRects(*this, *layout, accumulatedOffset));
+        return;
+    }
+
     if (!m_inlineBoxWrapper)
         return;
     rects.append(enclosingIntRect(FloatRect(accumulatedOffset + m_inlineBoxWrapper->topLeft(), m_inlineBoxWrapper->size())));
@@ -173,9 +211,13 @@ void RenderLineBreak::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& a
 
 void RenderLineBreak::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
 {
+    if (auto* layout = simpleLineLayout(*this)) {
+        quads.appendVector(SimpleLineLayout::collectAbsoluteQuads(*this, *layout, wasFixed));
+        return;
+    }
     if (!m_inlineBoxWrapper)
         return;
-    quads.append(localToAbsoluteQuad(FloatRect(m_inlineBoxWrapper->topLeft(), m_inlineBoxWrapper->size()), 0 /* mode */, wasFixed));
+    quads.append(localToAbsoluteQuad(FloatRect(m_inlineBoxWrapper->topLeft(), m_inlineBoxWrapper->size()), UseTransforms, wasFixed));
 }
 
 void RenderLineBreak::updateFromStyle()
@@ -183,9 +225,58 @@ void RenderLineBreak::updateFromStyle()
     m_cachedLineHeight = invalidLineHeight;
 }
 
-IntRect RenderLineBreak::borderBoundingBox() const
+#if PLATFORM(IOS)
+void RenderLineBreak::collectSelectionRects(Vector<SelectionRect>& rects, unsigned, unsigned)
 {
-    return IntRect(IntPoint(), linesBoundingBox().size());
+    ensureLineBoxes(*this);
+    InlineElementBox* box = m_inlineBoxWrapper;
+    if (!box)
+        return;
+    const RootInlineBox& rootBox = box->root();
+    LayoutRect rect = rootBox.computeCaretRect(box->logicalLeft(), 0, nullptr);
+    if (rootBox.isFirstAfterPageBreak()) {
+        if (box->isHorizontal())
+            rect.shiftYEdgeTo(rootBox.lineTopWithLeading());
+        else
+            rect.shiftXEdgeTo(rootBox.lineTopWithLeading());
+    }
+
+    auto* containingBlock = containingBlockForObjectInFlow();
+    // Map rect, extended left to leftOffset, and right to rightOffset, through transforms to get minX and maxX.
+    LogicalSelectionOffsetCaches cache(*containingBlock);
+    LayoutUnit leftOffset = containingBlock->logicalLeftSelectionOffset(*containingBlock, box->logicalTop(), cache);
+    LayoutUnit rightOffset = containingBlock->logicalRightSelectionOffset(*containingBlock, box->logicalTop(), cache);
+    LayoutRect extentsRect = rect;
+    if (box->isHorizontal()) {
+        extentsRect.setX(leftOffset);
+        extentsRect.setWidth(rightOffset - leftOffset);
+    } else {
+        extentsRect.setY(leftOffset);
+        extentsRect.setHeight(rightOffset - leftOffset);
+    }
+    extentsRect = localToAbsoluteQuad(FloatRect(extentsRect)).enclosingBoundingBox();
+    if (!box->isHorizontal())
+        extentsRect = extentsRect.transposedRect();
+    bool isFirstOnLine = !box->previousOnLineExists();
+    bool isLastOnLine = !box->nextOnLineExists();
+    if (containingBlock->isRubyBase() || containingBlock->isRubyText())
+        isLastOnLine = !containingBlock->containingBlock()->inlineBoxWrapper()->nextOnLineExists();
+
+    bool isFixed = false;
+    IntRect absRect = localToAbsoluteQuad(FloatRect(rect), UseTransforms, &isFixed).enclosingBoundingBox();
+    bool boxIsHorizontal = !box->isSVGInlineTextBox() ? box->isHorizontal() : !style().isVerticalWritingMode();
+    // If the containing block is an inline element, we want to check the inlineBoxWrapper orientation
+    // to determine the orientation of the block. In this case we also use the inlineBoxWrapper to
+    // determine if the element is the last on the line.
+    if (containingBlock->inlineBoxWrapper()) {
+        if (containingBlock->inlineBoxWrapper()->isHorizontal() != boxIsHorizontal) {
+            boxIsHorizontal = containingBlock->inlineBoxWrapper()->isHorizontal();
+            isLastOnLine = !containingBlock->inlineBoxWrapper()->nextOnLineExists();
+        }
+    }
+
+    rects.append(SelectionRect(absRect, box->direction(), extentsRect.x(), extentsRect.maxX(), extentsRect.maxY(), 0, box->isLineBreak(), isFirstOnLine, isLastOnLine, false, false, boxIsHorizontal, isFixed, containingBlock->isRubyText(), view().pageNumberForBlockProgressionOffset(absRect.x())));
 }
+#endif
 
 } // namespace WebCore