RenderMathMLMenclose.cpp [plain text]
#include "config.h"
#if ENABLE(MATHML)
#include "RenderMathMLMenclose.h"
#include "GraphicsContext.h"
#include "MathMLNames.h"
#include "PaintInfo.h"
#include <wtf/MathExtras.h>
namespace WebCore {
using namespace MathMLNames;
const unsigned short longDivLeftSpace = 10;
RenderMathMLMenclose::RenderMathMLMenclose(Element& element, RenderStyle&& style)
: RenderMathMLRow(element, WTFMove(style))
, m_ascent(0)
{
}
LayoutUnit RenderMathMLMenclose::ruleThickness() const
{
return 0.05f * style().fontCascade().size();
}
void RenderMathMLMenclose::getSpaceAroundContent(LayoutUnit contentWidth, LayoutUnit contentHeight, LayoutUnit& leftSpace, LayoutUnit& rightSpace, LayoutUnit& topSpace, LayoutUnit& bottomSpace) const
{
leftSpace = rightSpace = topSpace = bottomSpace = 0;
LayoutUnit thickness = ruleThickness();
if (hasNotation(MathMLMencloseElement::Left))
leftSpace = std::max(leftSpace, 5 * thickness);
if (hasNotation(MathMLMencloseElement::Right))
rightSpace = std::max(rightSpace, 5 * thickness);
if (hasNotation(MathMLMencloseElement::Left) || hasNotation(MathMLMencloseElement::Right)) {
LayoutUnit extraSpace = 4 * thickness;
topSpace = std::max(topSpace, extraSpace);
bottomSpace = std::max(bottomSpace, extraSpace);
}
if (hasNotation(MathMLMencloseElement::Top))
topSpace = std::max(topSpace, 5 * thickness);
if (hasNotation(MathMLMencloseElement::Bottom))
bottomSpace = std::max(bottomSpace, 5 * thickness);
if (hasNotation(MathMLMencloseElement::Top) || hasNotation(MathMLMencloseElement::Bottom)) {
LayoutUnit extraSpace = 4 * thickness;
leftSpace = std::max(leftSpace, extraSpace);
rightSpace = std::max(rightSpace, extraSpace);
}
if (hasNotation(MathMLMencloseElement::LongDiv)) {
topSpace = std::max(topSpace, 5 * thickness);
bottomSpace = std::max(bottomSpace, 5 * thickness);
leftSpace = std::max(leftSpace, longDivLeftSpace * thickness);
rightSpace = std::max(rightSpace, 4 * thickness);
}
if (hasNotation(MathMLMencloseElement::RoundedBox)) {
LayoutUnit extraSpace = 5 * thickness;
leftSpace = std::max(leftSpace, extraSpace);
rightSpace = std::max(rightSpace, extraSpace);
topSpace = std::max(topSpace, extraSpace);
bottomSpace = std::max(bottomSpace, extraSpace);
}
if (hasNotation(MathMLMencloseElement::UpDiagonalStrike) || hasNotation(MathMLMencloseElement::DownDiagonalStrike)) {
LayoutUnit extraSpace = thickness / 2;
leftSpace = std::max(leftSpace, extraSpace);
rightSpace = std::max(rightSpace, extraSpace);
topSpace = std::max(topSpace, extraSpace);
bottomSpace = std::max(bottomSpace, extraSpace);
}
if (hasNotation(MathMLMencloseElement::Circle)) {
LayoutUnit extraSpace = (contentWidth * (sqrtOfTwoFloat - 1) + 3 * thickness) / 2;
leftSpace = std::max(leftSpace, extraSpace);
rightSpace = std::max(rightSpace, extraSpace);
extraSpace = (contentHeight * (sqrtOfTwoFloat - 1) + 3 * thickness) / 2;
topSpace = std::max(topSpace, extraSpace);
bottomSpace = std::max(bottomSpace, extraSpace);
}
}
void RenderMathMLMenclose::computePreferredLogicalWidths()
{
ASSERT(preferredLogicalWidthsDirty());
RenderMathMLRow::computePreferredLogicalWidths();
LayoutUnit preferredWidth = m_maxPreferredLogicalWidth;
LayoutUnit leftSpace, rightSpace, dummy;
getSpaceAroundContent(preferredWidth, 0, leftSpace, rightSpace, dummy, dummy);
m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = leftSpace + preferredWidth + rightSpace;
setPreferredLogicalWidthsDirty(false);
}
void RenderMathMLMenclose::layoutBlock(bool relayoutChildren, LayoutUnit)
{
ASSERT(needsLayout());
if (!relayoutChildren && simplifiedLayout())
return;
LayoutUnit contentAscent = 0;
LayoutUnit contentDescent = 0;
RenderMathMLRow::computeLineVerticalStretch(contentAscent, contentDescent);
RenderMathMLRow::layoutRowItems(contentAscent, contentDescent);
LayoutUnit contentWidth = logicalWidth();
LayoutUnit leftSpace, rightSpace, topSpace, bottomSpace;
getSpaceAroundContent(contentWidth, contentAscent + contentDescent, leftSpace, rightSpace, topSpace, bottomSpace);
setLogicalWidth(leftSpace + contentWidth + rightSpace);
m_ascent = topSpace + contentAscent;
LayoutUnit descent = contentDescent + bottomSpace;
LayoutPoint contentLocation(leftSpace, m_ascent - contentAscent);
for (auto* child = firstChildBox(); child; child = child->nextSiblingBox())
child->setLocation(child->location() + contentLocation);
setLogicalHeight(m_ascent + descent);
m_contentRect = LayoutRect(leftSpace, topSpace, contentWidth, contentAscent + contentDescent);
clearNeedsLayout();
}
Optional<int> RenderMathMLMenclose::firstLineBaseline() const
{
return Optional<int>(static_cast<int>(lroundf(m_ascent)));
}
static void drawLine(PaintInfo& info, const LayoutUnit& xStart, const LayoutUnit& yStart, const LayoutUnit& xEnd, const LayoutUnit& yEnd)
{
Path line;
line.moveTo(LayoutPoint(xStart, yStart));
line.addLineTo(LayoutPoint(xEnd, yEnd));
info.context().strokePath(line);
}
void RenderMathMLMenclose::paint(PaintInfo& info, const LayoutPoint& paintOffset)
{
RenderMathMLRow::paint(info, paintOffset);
if (info.context().paintingDisabled() || info.phase != PaintPhaseForeground || style().visibility() != VISIBLE)
return;
LayoutUnit thickness = ruleThickness();
GraphicsContextStateSaver stateSaver(info.context());
info.context().setStrokeThickness(thickness);
info.context().setStrokeStyle(SolidStroke);
info.context().setStrokeColor(style().visitedDependentColor(CSSPropertyColor));
info.context().setFillColor(Color::transparent);
info.applyTransform(AffineTransform().translate(paintOffset + location()));
if (hasNotation(MathMLMencloseElement::Left)) {
LayoutUnit x = m_contentRect.x() - 7 * thickness / 2;
LayoutUnit yStart = m_contentRect.y() - 4 * thickness;
LayoutUnit yEnd = m_contentRect.maxY() + 4 * thickness;
drawLine(info, x, yStart, x, yEnd);
}
if (hasNotation(MathMLMencloseElement::Right)) {
LayoutUnit x = m_contentRect.maxX() + 7 * thickness / 2;
LayoutUnit yStart = m_contentRect.y() - 4 * thickness;
LayoutUnit yEnd = m_contentRect.maxY() + 4 * thickness;
drawLine(info, x, yStart, x, yEnd);
}
if (hasNotation(MathMLMencloseElement::VerticalStrike)) {
LayoutUnit x = m_contentRect.x() + (m_contentRect.width() - thickness) / 2;
LayoutUnit yStart = m_contentRect.y();
LayoutUnit yEnd = m_contentRect.maxY();
drawLine(info, x, yStart, x, yEnd);
}
if (hasNotation(MathMLMencloseElement::Top)) {
LayoutUnit y = m_contentRect.y() - 7 * thickness / 2;
LayoutUnit xStart = m_contentRect.x() - 4 * thickness;
LayoutUnit xEnd = m_contentRect.maxX() + 4 * thickness;
drawLine(info, xStart, y, xEnd, y);
}
if (hasNotation(MathMLMencloseElement::Bottom)) {
LayoutUnit y = m_contentRect.maxY() + 7 * thickness / 2;
LayoutUnit xStart = m_contentRect.x() - 4 * thickness;
LayoutUnit xEnd = m_contentRect.maxX() + 4 * thickness;
drawLine(info, xStart, y, xEnd, y);
}
if (hasNotation(MathMLMencloseElement::HorizontalStrike)) {
LayoutUnit y = m_contentRect.y() + (m_contentRect.height() - thickness) / 2;
LayoutUnit xStart = m_contentRect.x();
LayoutUnit xEnd = m_contentRect.maxX();
drawLine(info, xStart, y, xEnd, y);
}
if (hasNotation(MathMLMencloseElement::UpDiagonalStrike))
drawLine(info, m_contentRect.x(), m_contentRect.maxY(), m_contentRect.maxX(), m_contentRect.y());
if (hasNotation(MathMLMencloseElement::DownDiagonalStrike))
drawLine(info, m_contentRect.x(), m_contentRect.y(), m_contentRect.maxX(), m_contentRect.maxY());
if (hasNotation(MathMLMencloseElement::RoundedBox)) {
LayoutSize radiiSize(3 * thickness, 3 * thickness);
RoundedRect::Radii radii(radiiSize, radiiSize, radiiSize, radiiSize);
RoundedRect roundedRect(m_contentRect, radii);
roundedRect.inflate(7 * thickness / 2);
Path path;
path.addRoundedRect(roundedRect);
info.context().strokePath(path);
}
if (hasNotation(MathMLMencloseElement::LongDiv)) {
LayoutUnit top = m_contentRect.y() - 7 * thickness / 2;
LayoutUnit bottom = m_contentRect.maxY() + 7 * thickness / 2;
LayoutUnit left = m_contentRect.x() - longDivLeftSpace * thickness + thickness / 2;
LayoutUnit right = m_contentRect.maxX() + 4 * thickness;
LayoutUnit midX = left + longDivLeftSpace * thickness;
LayoutUnit midY = (top + bottom) / 2;
Path path;
path.moveTo(LayoutPoint(right, top));
path.addLineTo(LayoutPoint(left, top));
path.addQuadCurveTo(LayoutPoint(midX, midY), FloatPoint(left, bottom));
info.context().strokePath(path);
}
if (hasNotation(MathMLMencloseElement::Circle)) {
LayoutRect ellipseRect;
ellipseRect.setWidth(m_contentRect.width() * sqrtOfTwoFloat + thickness);
ellipseRect.setHeight(m_contentRect.height() * sqrtOfTwoFloat + thickness);
ellipseRect.setX(m_contentRect.x() - (ellipseRect.width() - m_contentRect.width()) / 2);
ellipseRect.setY(m_contentRect.y() - (ellipseRect.height() - m_contentRect.height()) / 2);
Path path;
path.addEllipse(ellipseRect);
info.context().strokePath(path);
}
}
}
#endif // ENABLE(MATHML)