~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/rendering/mathml/RenderMathMLFenced.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2009 Alex Milowski (alex@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
#include <wtf/text/StringBuilder.h>
 
38
 
 
39
namespace WebCore {
 
40
    
 
41
using namespace MathMLNames;
 
42
    
 
43
enum Braces { OpeningBraceChar = 0x28, ClosingBraceChar = 0x29 };
 
44
    
 
45
static const float gSeparatorMarginEndEms = 0.25f;
 
46
static const float gFenceMarginEms = 0.1f;
 
47
 
 
48
RenderMathMLFenced::RenderMathMLFenced(Element* element)
 
49
    : RenderMathMLRow(element)
 
50
    , m_open(OpeningBraceChar)
 
51
    , m_close(ClosingBraceChar)
 
52
    , m_closeFenceRenderer(0)
 
53
{
 
54
}
 
55
 
 
56
void RenderMathMLFenced::updateFromElement()
 
57
{
 
58
    Element* fenced = static_cast<Element*>(node());
 
59
 
 
60
    // FIXME: Handle open/close values with more than one character (they should be treated like text).
 
61
    AtomicString openValue = fenced->getAttribute(MathMLNames::openAttr);
 
62
    if (openValue.length() > 0)
 
63
        m_open = openValue[0];
 
64
    AtomicString closeValue = fenced->getAttribute(MathMLNames::closeAttr);
 
65
    if (closeValue.length() > 0)
 
66
        m_close = closeValue[0];
 
67
    
 
68
    AtomicString separators = fenced->getAttribute(MathMLNames::separatorsAttr);
 
69
    if (!separators.isNull()) {
 
70
        StringBuilder characters;
 
71
        for (unsigned int i = 0; i < separators.length(); i++) {
 
72
            if (!isSpaceOrNewline(separators[i]))
 
73
                characters.append(separators[i]);
 
74
        }
 
75
        m_separators = !characters.length() ? 0 : characters.toString().impl();
 
76
    } else {
 
77
        // The separator defaults to a single comma.
 
78
        m_separators = StringImpl::create(",");
 
79
    }
 
80
    
 
81
    if (isEmpty())
 
82
        makeFences();
 
83
}
 
84
 
 
85
RenderMathMLOperator* RenderMathMLFenced::createMathMLOperator(UChar uChar, RenderMathMLOperator::OperatorType operatorType)
 
86
{
 
87
    RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), FLEX);
 
88
    newStyle->setFlexDirection(FlowColumn);
 
89
    newStyle->setMarginEnd(Length((operatorType == RenderMathMLOperator::Fence ? gFenceMarginEms : gSeparatorMarginEndEms) * style()->fontSize(), Fixed));
 
90
    if (operatorType == RenderMathMLOperator::Fence)
 
91
        newStyle->setMarginStart(Length(gFenceMarginEms * style()->fontSize(), Fixed));
 
92
    RenderMathMLOperator* newOperator = new (renderArena()) RenderMathMLOperator(node() /* "almost anonymous" */, uChar);
 
93
    newOperator->setOperatorType(operatorType);
 
94
    newOperator->setStyle(newStyle.release());
 
95
    return newOperator;
 
96
}
 
97
 
 
98
void RenderMathMLFenced::makeFences()
 
99
{
 
100
    RenderMathMLRow::addChild(createMathMLOperator(m_open, RenderMathMLOperator::Fence), firstChild());
 
101
    m_closeFenceRenderer = createMathMLOperator(m_close, RenderMathMLOperator::Fence);
 
102
    RenderMathMLRow::addChild(m_closeFenceRenderer);
 
103
}
 
104
 
 
105
void RenderMathMLFenced::addChild(RenderObject* child, RenderObject* beforeChild)
 
106
{
 
107
    // make the fences if the render object is empty
 
108
    if (isEmpty())
 
109
        updateFromElement();
 
110
    
 
111
    // FIXME: Adding or removing a child should possibly cause all later separators to shift places if they're different,
 
112
    // as later child positions change by +1 or -1.
 
113
    
 
114
    RenderObject* separatorRenderer = 0;
 
115
    if (m_separators.get()) {
 
116
        unsigned int count = 0;
 
117
        for (Node* position = child->node(); position; position = position->previousSibling()) {
 
118
            if (position->isElementNode())
 
119
                count++;
 
120
        }
 
121
        if (!beforeChild) {
 
122
            // We're adding at the end (before the closing fence), so a new separator would go before the new child, not after it.
 
123
            --count;
 
124
        }
 
125
        // |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.
 
126
        
 
127
        if (count > 0) {
 
128
            UChar separator;
 
129
            
 
130
            // Use the last separator if we've run out of specified separators.
 
131
            if (count > m_separators.get()->length())
 
132
                separator = (*m_separators.get())[m_separators.get()->length() - 1];
 
133
            else
 
134
                separator = (*m_separators.get())[count - 1];
 
135
                
 
136
            separatorRenderer = createMathMLOperator(separator, RenderMathMLOperator::Separator);
 
137
        }
 
138
    }
 
139
    
 
140
    if (beforeChild) {
 
141
        // Adding |x| before an existing |y| e.g. in element (y) - first insert our new child |x|, then its separator, to get (x, y).
 
142
        RenderMathMLRow::addChild(child, beforeChild);
 
143
        if (separatorRenderer)
 
144
            RenderMathMLRow::addChild(separatorRenderer, beforeChild);
 
145
    } else {
 
146
        // 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).
 
147
        if (separatorRenderer)
 
148
            RenderMathMLRow::addChild(separatorRenderer, m_closeFenceRenderer);
 
149
        RenderMathMLRow::addChild(child, m_closeFenceRenderer);
 
150
    }
 
151
}
 
152
 
 
153
// FIXME: Change createMathMLOperator() above to create an isAnonymous() operator, and remove this styleDidChange() function.
 
154
void RenderMathMLFenced::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
 
155
{
 
156
    RenderMathMLBlock::styleDidChange(diff, oldStyle);
 
157
    
 
158
    for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
 
159
        if (child->node() == node()) {
 
160
            ASSERT(child->style()->refCount() == 1);
 
161
            child->style()->inheritFrom(style());
 
162
            bool isFence = child == firstChild() || child == lastChild();
 
163
            child->style()->setMarginEnd(Length((isFence ? gFenceMarginEms : gSeparatorMarginEndEms) * style()->fontSize(), Fixed));
 
164
            if (isFence)
 
165
                child->style()->setMarginStart(Length(gFenceMarginEms * style()->fontSize(), Fixed));
 
166
        }
 
167
    }
 
168
}
 
169
 
 
170
}    
 
171
 
 
172
#endif