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