RenderMathMLSubSup.cpp [plain text]
#include "config.h"
#if ENABLE(MATHML)
#include "RenderMathMLSubSup.h"
#include "MathMLNames.h"
namespace WebCore {
using namespace MathMLNames;
RenderMathMLSubSup::RenderMathMLSubSup(Element* element)
: RenderMathMLBlock(element)
, m_scripts(0)
{
if (element->hasLocalName(MathMLNames::msubTag))
m_kind = Sub;
else if (element->hasLocalName(MathMLNames::msupTag))
m_kind = Super;
else {
ASSERT(element->hasLocalName(MathMLNames::msubsupTag));
m_kind = SubSup;
}
}
RenderBoxModelObject* RenderMathMLSubSup::base() const
{
RenderObject* baseWrapper = firstChild();
if (!baseWrapper)
return 0;
RenderObject* base = baseWrapper->firstChild();
if (!base || !base->isBoxModelObject())
return 0;
return toRenderBoxModelObject(base);
}
void RenderMathMLSubSup::fixAnonymousStyles()
{
ASSERT(firstChild() && firstChild()->style()->refCount() == 1);
firstChild()->style()->setAlignSelf(AlignFlexStart);
ASSERT(m_scripts && m_scripts->style()->refCount() == 1);
RenderStyle* scriptsStyle = m_scripts->style();
scriptsStyle->setFlexDirection(FlowColumn);
scriptsStyle->setJustifyContent(m_kind == Sub ? JustifyFlexEnd : m_kind == Super ? JustifyFlexStart : JustifySpaceBetween);
scriptsStyle->setFontSize(static_cast<int>(0.75 * style()->fontSize()));
}
void RenderMathMLSubSup::addChild(RenderObject* child, RenderObject* beforeChild)
{
if (isEmpty()) {
RenderMathMLBlock* baseWrapper = createAnonymousMathMLBlock();
RenderMathMLBlock::addChild(baseWrapper);
m_scripts = createAnonymousMathMLBlock();
RenderMathMLBlock::addChild(m_scripts);
fixAnonymousStyles();
}
if (firstChild()->isEmpty())
firstChild()->addChild(child);
else
m_scripts->addChild(child, beforeChild && beforeChild->parent() == m_scripts ? beforeChild : 0);
}
void RenderMathMLSubSup::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
RenderMathMLBlock::styleDidChange(diff, oldStyle);
if (!isEmpty())
fixAnonymousStyles();
}
RenderMathMLOperator* RenderMathMLSubSup::unembellishedOperator()
{
RenderBoxModelObject* base = this->base();
if (!base || !base->isRenderMathMLBlock())
return 0;
return toRenderMathMLBlock(base)->unembellishedOperator();
}
void RenderMathMLSubSup::layout()
{
RenderMathMLBlock::layout();
RenderMathMLBlock* baseWrapper = toRenderMathMLBlock(firstChild());
if (!baseWrapper || !m_scripts)
return;
RenderBox* base = baseWrapper->firstChildBox();
if (!base)
return;
LayoutUnit baseHeight = base->logicalHeight();
LayoutUnit baseBaseline = base->firstLineBoxBaseline();
if (baseBaseline == -1)
baseBaseline = baseHeight;
LayoutUnit axis = style()->fontMetrics().xHeight() / 2;
int fontSize = style()->fontSize();
ASSERT(baseWrapper->style()->hasOneRef());
bool needsSecondLayout = false;
if (RenderBox* superscript = m_kind == Sub ? 0 : m_scripts->lastChildBox()) {
LayoutUnit superscriptHeight = superscript->logicalHeight();
LayoutUnit superscriptBaseline = superscript->firstLineBoxBaseline();
if (superscriptBaseline == -1)
superscriptBaseline = superscriptHeight;
LayoutUnit minBaseline = max<LayoutUnit>(fontSize / 3 + 1 + superscriptBaseline, superscriptHeight + axis);
Length newPadding = Length(max<LayoutUnit>(minBaseline - baseBaseline, 0), Fixed);
if (newPadding != baseWrapper->style()->paddingTop()) {
baseWrapper->style()->setPaddingTop(newPadding);
needsSecondLayout = true;
}
}
if (RenderBox* subscript = m_kind == Super ? 0 : m_scripts->firstChildBox()) {
LayoutUnit subscriptHeight = subscript->logicalHeight();
LayoutUnit subscriptBaseline = subscript->firstLineBoxBaseline();
if (subscriptBaseline == -1)
subscriptBaseline = subscriptHeight;
LayoutUnit baseExtendUnderBaseline = baseHeight - baseBaseline;
LayoutUnit subscriptUnderItsBaseline = subscriptHeight - subscriptBaseline;
LayoutUnit minExtendUnderBaseline = max<LayoutUnit>(fontSize / 5 + 1 + subscriptUnderItsBaseline, subscriptHeight - axis);
Length newPadding = Length(max<LayoutUnit>(minExtendUnderBaseline - baseExtendUnderBaseline, 0), Fixed);
if (newPadding != baseWrapper->style()->paddingBottom()) {
baseWrapper->style()->setPaddingBottom(newPadding);
needsSecondLayout = true;
}
}
if (!needsSecondLayout)
return;
setNeedsLayout(true, MarkOnlyThis);
baseWrapper->setChildNeedsLayout(true, MarkOnlyThis);
RenderMathMLBlock::layout();
}
}
#endif // ENABLE(MATHML)