Home | History | Annotate | Download | only in mathml
      1 /*
      2  * Copyright (C) 2009 Alex Milowski (alex (at) milowski.com). All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     14  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     15  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     16  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     17  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     18  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     19  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 
     28 #if ENABLE(MATHML)
     29 
     30 #include "RenderMathMLFenced.h"
     31 
     32 #include "FontSelector.h"
     33 #include "MathMLNames.h"
     34 #include "RenderInline.h"
     35 #include "RenderMathMLOperator.h"
     36 #include "RenderText.h"
     37 
     38 namespace WebCore {
     39 
     40 using namespace MathMLNames;
     41 
     42 enum Braces { OpeningBraceChar = 0x28, ClosingBraceChar = 0x29 };
     43 
     44 static const float gOperatorPadding = 0.1f;
     45 
     46 RenderMathMLFenced::RenderMathMLFenced(Node* fenced)
     47     : RenderMathMLRow(fenced)
     48     , m_open(OpeningBraceChar)
     49     , m_close(ClosingBraceChar)
     50 {
     51 }
     52 
     53 void RenderMathMLFenced::updateFromElement()
     54 {
     55     Element* fenced = static_cast<Element*>(node());
     56 
     57     // FIXME: Handle open/close values with more than one character (they should be treated like text).
     58     AtomicString openValue = fenced->getAttribute(MathMLNames::openAttr);
     59     if (openValue.length() > 0)
     60         m_open = openValue[0];
     61     AtomicString closeValue = fenced->getAttribute(MathMLNames::closeAttr);
     62     if (closeValue.length() > 0)
     63         m_close = closeValue[0];
     64 
     65     AtomicString separators = static_cast<Element*>(fenced)->getAttribute(MathMLNames::separatorsAttr);
     66     if (!separators.isNull()) {
     67         Vector<UChar> characters;
     68         for (unsigned int i = 0; i < separators.length(); i++) {
     69             if (!isSpaceOrNewline(separators[i]))
     70                 characters.append(separators[i]);
     71         }
     72         m_separators = !characters.size() ? 0 : StringImpl::create(characters.data() , characters.size());
     73     } else {
     74         // The separator defaults to a single comma.
     75         m_separators = StringImpl::create(",");
     76     }
     77 
     78     if (isEmpty())
     79         makeFences();
     80 }
     81 
     82 RefPtr<RenderStyle> RenderMathMLFenced::makeOperatorStyle()
     83 {
     84     RefPtr<RenderStyle> newStyle = RenderStyle::create();
     85     newStyle->inheritFrom(style());
     86     newStyle->setDisplay(INLINE_BLOCK);
     87     newStyle->setPaddingRight(Length(static_cast<int>(gOperatorPadding * style()->fontSize()), Fixed));
     88     return newStyle;
     89 }
     90 
     91 void RenderMathMLFenced::makeFences()
     92 {
     93     RenderObject* openFence = new (renderArena()) RenderMathMLOperator(node(), m_open);
     94     openFence->setStyle(makeOperatorStyle().release());
     95     RenderBlock::addChild(openFence, firstChild());
     96     RenderObject* closeFence = new (renderArena()) RenderMathMLOperator(node(), m_close);
     97     closeFence->setStyle(makeOperatorStyle().release());
     98     RenderBlock::addChild(closeFence);
     99 }
    100 
    101 void RenderMathMLFenced::addChild(RenderObject* child, RenderObject*)
    102 {
    103     // make the fences if the render object is empty
    104     if (isEmpty())
    105         updateFromElement();
    106 
    107     if (m_separators.get()) {
    108         unsigned int count = 0;
    109         for (Node* position = child->node(); position; position = position->previousSibling()) {
    110             if (position->nodeType() == Node::ELEMENT_NODE)
    111                 count++;
    112         }
    113 
    114         if (count > 1) {
    115             UChar separator;
    116 
    117             // Use the last separator if we've run out of specified separators.
    118             if ((count - 1) >= m_separators.get()->length())
    119                 separator = (*m_separators.get())[m_separators.get()->length() - 1];
    120             else
    121                 separator = (*m_separators.get())[count - 1];
    122 
    123             RenderObject* separatorObj = new (renderArena()) RenderMathMLOperator(node(), separator);
    124             separatorObj->setStyle(makeOperatorStyle().release());
    125             RenderBlock::addChild(separatorObj, lastChild());
    126         }
    127     }
    128 
    129     // If we have a block, we'll wrap it in an inline-block.
    130     if (child->isBlockFlow() && child->style()->display() != INLINE_BLOCK) {
    131         // Block objects wrapper.
    132 
    133         RenderBlock* block = new (renderArena()) RenderBlock(node());
    134         RefPtr<RenderStyle> newStyle = RenderStyle::create();
    135         newStyle->inheritFrom(style());
    136         newStyle->setDisplay(INLINE_BLOCK);
    137         block->setStyle(newStyle.release());
    138 
    139         RenderBlock::addChild(block, lastChild());
    140         block->addChild(child);
    141     } else
    142         RenderBlock::addChild(child, lastChild());
    143 }
    144 
    145 }
    146 
    147 #endif
    148