RenderMathMLUnderOver.cpp [plain text]
#include "config.h"
#if ENABLE(MATHML)
#include "RenderMathMLUnderOver.h"
#include "FontSelector.h"
#include "MathMLNames.h"
namespace WebCore {
using namespace MathMLNames;
static const double gOverSpacingAdjustment = 0.5;
RenderMathMLUnderOver::RenderMathMLUnderOver(Node* expression)
: RenderMathMLBlock(expression)
{
Element* element = static_cast<Element*>(expression);
if (element->hasLocalName(MathMLNames::munderTag))
m_kind = Under;
else if (element->hasLocalName(MathMLNames::moverTag))
m_kind = Over;
else if (element->hasLocalName(MathMLNames::munderoverTag))
m_kind = UnderOver;
else
m_kind = Under;
}
void RenderMathMLUnderOver::addChild(RenderObject* child, RenderObject* beforeChild)
{
RenderMathMLBlock* row = new (renderArena()) RenderMathMLBlock(node());
RefPtr<RenderStyle> rowStyle = makeBlockStyle();
row->setStyle(rowStyle.release());
int blocks = 0;
RenderObject* current = this->firstChild();
while (current) {
blocks++;
current = current->nextSibling();
}
switch (blocks) {
case 0:
RenderBlock::addChild(row, beforeChild);
break;
case 1:
row->style()->setTextAlign(CENTER);
if (m_kind == Over) {
RenderBlock::addChild(row, firstChild());
} else {
RenderBlock::addChild(row, beforeChild);
}
break;
case 2:
row->style()->setTextAlign(CENTER);
if (m_kind == UnderOver) {
RenderBlock::addChild(row, firstChild());
} else {
RenderBlock::addChild(row, beforeChild);
}
break;
default:
RenderBlock::addChild(row, beforeChild);
}
row->addChild(child);
}
inline int getOffsetHeight(RenderObject* obj)
{
if (obj->isBoxModelObject()) {
RenderBoxModelObject* box = toRenderBoxModelObject(obj);
return box->offsetHeight();
}
return 0;
}
void RenderMathMLUnderOver::stretchToHeight(int height)
{
RenderObject* base = firstChild();
if (!base)
return;
if (m_kind != Under)
base = base->nextSibling();
if (!base)
return;
base = base->firstChild();
if (base && base->isRenderMathMLBlock()) {
RenderMathMLBlock* block = toRenderMathMLBlock(base);
block->stretchToHeight(height);
setNeedsLayout(true);
}
}
void RenderMathMLUnderOver::layout()
{
RenderBlock::layout();
RenderObject* over = 0;
RenderObject* base = 0;
switch (m_kind) {
case Over:
over = firstChild();
if (over) {
if (!over->firstChild()->isBoxModelObject())
break;
int overSpacing = static_cast<int>(gOverSpacingAdjustment * (getOffsetHeight(over) - toRenderBoxModelObject(over->firstChild())->baselinePosition(AlphabeticBaseline, true, HorizontalLine)));
base = over->nextSibling();
if (base) {
if (overSpacing > 0)
base->style()->setMarginTop(Length(-overSpacing, Fixed));
else
base->style()->setMarginTop(Length(0, Fixed));
}
}
break;
case Under:
base = firstChild();
if (base) {
int baseHeight = getOffsetHeight(base);
base = base->firstChild();
if (!base->isBoxModelObject())
break;
int underSpacing = baseHeight - toRenderBoxModelObject(base)->baselinePosition(AlphabeticBaseline, true, HorizontalLine);
RenderObject* under = lastChild();
if (under && underSpacing > 0)
under->style()->setMarginTop(Length(-underSpacing, Fixed));
}
break;
case UnderOver:
over = firstChild();
if (over) {
if (!over->firstChild()->isBoxModelObject())
break;
int overSpacing = static_cast<int>(gOverSpacingAdjustment * (getOffsetHeight(over) - toRenderBoxModelObject(over->firstChild())->baselinePosition(AlphabeticBaseline, true, HorizontalLine)));
base = over->nextSibling();
if (base) {
if (overSpacing > 0)
base->style()->setMarginTop(Length(-overSpacing, Fixed));
int baseHeight = getOffsetHeight(base);
base = base->firstChild();
if (!base->isBoxModelObject())
break;
int underSpacing = baseHeight - toRenderBoxModelObject(base)->baselinePosition(AlphabeticBaseline, true, HorizontalLine);
RenderObject* under = lastChild();
if (under && under->firstChild()->isRenderInline() && underSpacing > 0)
under->style()->setMarginTop(Length(-underSpacing, Fixed));
}
}
break;
}
setNeedsLayout(true);
RenderBlock::layout();
}
int RenderMathMLUnderOver::baselinePosition(FontBaseline, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
{
RenderObject* current = firstChild();
if (!current)
return RenderBlock::baselinePosition(AlphabeticBaseline, firstLine, direction, linePositionMode);
int baseline = 0;
switch (m_kind) {
case UnderOver:
case Over:
baseline += getOffsetHeight(current);
current = current->nextSibling();
if (current) {
RenderObject* base = current->firstChild();
if (!base || !base->isBoxModelObject())
break;
baseline += toRenderBoxModelObject(base)->baselinePosition(AlphabeticBaseline, firstLine, HorizontalLine, linePositionMode);
baseline += current->style()->marginTop().value();
}
break;
case Under:
RenderObject* base = current->firstChild();
if (base && base->isBoxModelObject())
baseline += toRenderBoxModelObject(base)->baselinePosition(AlphabeticBaseline, true, HorizontalLine);
}
float zoomFactor = style()->effectiveZoom();
baseline += static_cast<int>((zoomFactor > 1.25 ? 2 : 3) * zoomFactor);
return baseline;
}
int RenderMathMLUnderOver::nonOperatorHeight() const
{
int nonOperators = 0;
for (RenderObject* current = firstChild(); current; current = current->nextSibling()) {
if (current->firstChild()->isRenderMathMLBlock()) {
RenderMathMLBlock* block = toRenderMathMLBlock(current->firstChild());
if (!block->isRenderMathMLOperator())
nonOperators += getOffsetHeight(current);
} else {
nonOperators += getOffsetHeight(current);
}
}
return nonOperators;
}
}
#endif // ENABLE(MATHML)