Replace PassRef with Ref/Ref&& across the board.
[WebKit-https.git] / Source / WebCore / rendering / mathml / RenderMathMLFenced.cpp
index 63818ec..363e3d3 100644 (file)
@@ -40,30 +40,28 @@ namespace WebCore {
     
 using namespace MathMLNames;
     
-enum Braces { OpeningBraceChar = 0x28, ClosingBraceChar = 0x29 };
-    
-static const float gOperatorPadding = 0.1f;
+static const char* gOpeningBraceChar = "(";
+static const char* gClosingBraceChar = ")";
 
-RenderMathMLFenced::RenderMathMLFenced(Node* fenced) 
-    : RenderMathMLRow(fenced)
-    , m_open(OpeningBraceChar)
-    , m_close(ClosingBraceChar)
+RenderMathMLFenced::RenderMathMLFenced(MathMLInlineContainerElement& element, Ref<RenderStyle>&& style)
+    : RenderMathMLRow(element, WTF::move(style))
+    , m_closeFenceRenderer(nullptr)
 {
 }
 
 void RenderMathMLFenced::updateFromElement()
 {
-    Element* fenced = static_cast<Element*>(node());
+    const auto& fenced = element();
  
-    // FIXME: Handle open/close values with more than one character (they should be treated like text).
-    AtomicString openValue = fenced->getAttribute(MathMLNames::openAttr);
-    if (openValue.length() > 0)
-        m_open = openValue[0];
-    AtomicString closeValue = fenced->getAttribute(MathMLNames::closeAttr);
-    if (closeValue.length() > 0)
-        m_close = closeValue[0];
-    
-    AtomicString separators = static_cast<Element*>(fenced)->getAttribute(MathMLNames::separatorsAttr);
+    // The open operator defaults to a left parenthesis.
+    AtomicString open = fenced.fastGetAttribute(MathMLNames::openAttr);
+    m_open = open.isNull() ? gOpeningBraceChar : open;
+
+    // The close operator defaults to a right parenthesis.
+    AtomicString close = fenced.fastGetAttribute(MathMLNames::closeAttr);
+    m_close = close.isNull() ? gClosingBraceChar : close;
+
+    AtomicString separators = fenced.fastGetAttribute(MathMLNames::separatorsAttr);
     if (!separators.isNull()) {
         StringBuilder characters;
         for (unsigned int i = 0; i < separators.length(); i++) {
@@ -78,69 +76,77 @@ void RenderMathMLFenced::updateFromElement()
     
     if (isEmpty())
         makeFences();
+    else {
+        // FIXME: The mfenced element fails to update dynamically when its open, close and separators attributes are changed (https://bugs.webkit.org/show_bug.cgi?id=57696).
+        downcast<RenderMathMLOperator>(*firstChild()).updateTokenContent(m_open);
+        m_closeFenceRenderer->updateTokenContent(m_close);
+    }
 }
 
-RefPtr<RenderStyle> RenderMathMLFenced::makeOperatorStyle() 
+RenderPtr<RenderMathMLOperator> RenderMathMLFenced::createMathMLOperator(const String& operatorString, MathMLOperatorDictionary::Form form, MathMLOperatorDictionary::Flag flag)
 {
-    RefPtr<RenderStyle> newStyle = RenderStyle::create();
-    newStyle->inheritFrom(style());
-    newStyle->setDisplay(INLINE_BLOCK);
-    newStyle->setPaddingRight(Length(static_cast<int>(gOperatorPadding * style()->fontSize()), Fixed));
-    return newStyle;
+    RenderPtr<RenderMathMLOperator> newOperator = createRenderer<RenderMathMLOperator>(document(), RenderStyle::createAnonymousStyleWithDisplay(&style(), FLEX), operatorString, form, flag);
+    newOperator->initializeStyle();
+    return newOperator;
 }
 
 void RenderMathMLFenced::makeFences()
 {
-    RenderObject* openFence = new (renderArena()) RenderMathMLOperator(node(), m_open);
-    openFence->setStyle(makeOperatorStyle().release());
-    RenderBlock::addChild(openFence, firstChild());
-    RenderObject* closeFence = new (renderArena()) RenderMathMLOperator(node(), m_close);
-    closeFence->setStyle(makeOperatorStyle().release());
-    RenderBlock::addChild(closeFence);
+    RenderPtr<RenderMathMLOperator> openFence = createMathMLOperator(m_open, MathMLOperatorDictionary::Prefix, MathMLOperatorDictionary::Fence);
+    RenderMathMLRow::addChild(openFence.leakPtr(), firstChild());
+
+    RenderPtr<RenderMathMLOperator> closeFence = createMathMLOperator(m_close, MathMLOperatorDictionary::Postfix, MathMLOperatorDictionary::Fence);
+    m_closeFenceRenderer = closeFence.get();
+    RenderMathMLRow::addChild(closeFence.leakPtr());
 }
 
-void RenderMathMLFenced::addChild(RenderObject* child, RenderObject*)
+void RenderMathMLFenced::addChild(RenderObject* child, RenderObject* beforeChild)
 {
     // make the fences if the render object is empty
     if (isEmpty())
         updateFromElement();
     
+    // FIXME: Adding or removing a child should possibly cause all later separators to shift places if they're different, as later child positions change by +1 or -1. This should also handle surrogate pairs. See https://bugs.webkit.org/show_bug.cgi?id=125938.
+    
+    RenderPtr<RenderMathMLOperator> separatorRenderer;
     if (m_separators.get()) {
         unsigned int count = 0;
         for (Node* position = child->node(); position; position = position->previousSibling()) {
-            if (position->nodeType() == Node::ELEMENT_NODE)
+            if (position->isElementNode())
                 count++;
         }
-                
-        if (count > 1) {
+        if (!beforeChild) {
+            // We're adding at the end (before the closing fence), so a new separator would go before the new child, not after it.
+            --count;
+        }
+        // |count| is now the number of element children that will be before our new separator, i.e. it's the 1-based index of the separator.
+        
+        if (count > 0) {
             UChar separator;
             
             // Use the last separator if we've run out of specified separators.
-            if ((count - 1) >= m_separators.get()->length())
+            if (count > m_separators.get()->length())
                 separator = (*m_separators.get())[m_separators.get()->length() - 1];
             else
                 separator = (*m_separators.get())[count - 1];
                 
-            RenderObject* separatorObj = new (renderArena()) RenderMathMLOperator(node(), separator);
-            separatorObj->setStyle(makeOperatorStyle().release());
-            RenderBlock::addChild(separatorObj, lastChild());
+            StringBuilder builder;
+            builder.append(separator);
+            separatorRenderer = createMathMLOperator(builder.toString(), MathMLOperatorDictionary::Infix, MathMLOperatorDictionary::Separator);
         }
     }
     
-    // If we have a block, we'll wrap it in an inline-block.
-    if (child->isBlockFlow() && child->style()->display() != INLINE_BLOCK) {
-        // Block objects wrapper.
-
-        RenderBlock* block = new (renderArena()) RenderBlock(node());
-        RefPtr<RenderStyle> newStyle = RenderStyle::create();
-        newStyle->inheritFrom(style());
-        newStyle->setDisplay(INLINE_BLOCK);
-        block->setStyle(newStyle.release());
-        
-        RenderBlock::addChild(block, lastChild());
-        block->addChild(child);    
-    } else
-        RenderBlock::addChild(child, lastChild());
+    if (beforeChild) {
+        // Adding |x| before an existing |y| e.g. in element (y) - first insert our new child |x|, then its separator, to get (x, y).
+        RenderMathMLRow::addChild(child, beforeChild);
+        if (separatorRenderer)
+            RenderMathMLRow::addChild(separatorRenderer.leakPtr(), beforeChild);
+    } else {
+        // Adding |y| at the end of an existing element e.g. (x) - insert the separator first before the closing fence, then |y|, to get (x, y).
+        if (separatorRenderer)
+            RenderMathMLRow::addChild(separatorRenderer.leakPtr(), m_closeFenceRenderer);
+        RenderMathMLRow::addChild(child, m_closeFenceRenderer);
+    }
 }
 
 }