RenderMathMLUnderOver.cpp [plain text]
#include "config.h"
#if ENABLE(MATHML)
#include "RenderMathMLUnderOver.h"
#include "MathMLNames.h"
namespace WebCore {
using namespace MathMLNames;
static const double gOverSpacingAdjustment = 0.5;
RenderMathMLUnderOver::RenderMathMLUnderOver(Element* element)
: RenderMathMLBlock(element)
{
if (element->hasLocalName(MathMLNames::munderTag))
m_kind = Under;
else if (element->hasLocalName(MathMLNames::moverTag))
m_kind = Over;
else {
ASSERT(element->hasLocalName(MathMLNames::munderoverTag));
m_kind = UnderOver;
}
}
RenderBoxModelObject* RenderMathMLUnderOver::base() const
{
RenderObject* baseWrapper = firstChild();
if ((m_kind == Over || m_kind == UnderOver) && baseWrapper)
baseWrapper = baseWrapper->nextSibling();
if (!baseWrapper)
return 0;
RenderObject* base = baseWrapper->firstChild();
if (!base || !base->isBoxModelObject())
return 0;
return toRenderBoxModelObject(base);
}
void RenderMathMLUnderOver::addChild(RenderObject* child, RenderObject* beforeChild)
{
RenderBlock* row = createAnonymousBlock();
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);
}
RenderMathMLOperator* RenderMathMLUnderOver::unembellishedOperator()
{
RenderBoxModelObject* base = this->base();
if (!base || !base->isRenderMathMLBlock())
return 0;
return toRenderMathMLBlock(base)->unembellishedOperator();
}
inline int getOffsetHeight(RenderObject* obj)
{
if (obj->isBoxModelObject()) {
RenderBoxModelObject* box = toRenderBoxModelObject(obj);
return box->pixelSnappedOffsetHeight();
}
return 0;
}
void RenderMathMLUnderOver::layout()
{
RenderBlock::layout();
RenderObject* over = 0;
RenderObject* base = 0;
switch (m_kind) {
case Over:
over = firstChild();
if (over) {
if (!over->firstChild() || !over->firstChild()->isBoxModelObject())
break;
LayoutUnit overSpacing = static_cast<LayoutUnit>(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 || !base->isBoxModelObject())
break;
LayoutUnit 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() || !over->firstChild()->isBoxModelObject())
break;
LayoutUnit overSpacing = static_cast<LayoutUnit>(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 || !base->isBoxModelObject())
break;
LayoutUnit underSpacing = baseHeight - toRenderBoxModelObject(base)->baselinePosition(AlphabeticBaseline, true, HorizontalLine);
RenderObject* under = lastChild();
if (under && under->firstChild() && under->firstChild()->isRenderInline() && underSpacing > 0)
under->style()->setMarginTop(Length(-underSpacing, Fixed));
}
}
break;
}
setNeedsLayout(true);
RenderBlock::layout();
}
LayoutUnit RenderMathMLUnderOver::baselinePosition(FontBaseline, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
{
RenderObject* current = firstChild();
if (!current || linePositionMode == PositionOfInteriorLineBoxes)
return RenderBlock::baselinePosition(AlphabeticBaseline, firstLine, direction, linePositionMode);
LayoutUnit 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);
}
return baseline;
}
}
#endif // ENABLE(MATHML)