SVGTextLayoutEngineBaseline.cpp [plain text]
#include "config.h"
#include "SVGTextLayoutEngineBaseline.h"
#include "FontCascade.h"
#include "RenderElement.h"
#include "SVGLengthContext.h"
#include "SVGRenderStyle.h"
#include "SVGTextMetrics.h"
namespace WebCore {
SVGTextLayoutEngineBaseline::SVGTextLayoutEngineBaseline(const FontCascade& font)
: m_font(font)
{
}
float SVGTextLayoutEngineBaseline::calculateBaselineShift(const SVGRenderStyle& style, SVGElement* context) const
{
if (style.baselineShift() == BaselineShift::Length) {
auto baselineShiftValueLength = style.baselineShiftValue();
if (baselineShiftValueLength.unitType() == LengthTypePercentage)
return baselineShiftValueLength.valueAsPercentage() * m_font.pixelSize();
SVGLengthContext lengthContext(context);
return baselineShiftValueLength.value(lengthContext);
}
switch (style.baselineShift()) {
case BaselineShift::Baseline:
return 0;
case BaselineShift::Sub:
return -m_font.fontMetrics().floatHeight() / 2;
case BaselineShift::Super:
return m_font.fontMetrics().floatHeight() / 2;
case BaselineShift::Length:
break;
}
ASSERT_NOT_REACHED();
return 0;
}
AlignmentBaseline SVGTextLayoutEngineBaseline::dominantBaselineToAlignmentBaseline(bool isVerticalText, const RenderObject* textRenderer) const
{
ASSERT(textRenderer);
ASSERT(textRenderer->parent());
const SVGRenderStyle& svgStyle = textRenderer->style().svgStyle();
DominantBaseline baseline = svgStyle.dominantBaseline();
if (baseline == DominantBaseline::Auto) {
if (isVerticalText)
baseline = DominantBaseline::Central;
else
baseline = DominantBaseline::Alphabetic;
}
switch (baseline) {
case DominantBaseline::UseScript:
return AlignmentBaseline::Alphabetic;
case DominantBaseline::NoChange:
return dominantBaselineToAlignmentBaseline(isVerticalText, textRenderer->parent());
case DominantBaseline::ResetSize:
return dominantBaselineToAlignmentBaseline(isVerticalText, textRenderer->parent());
case DominantBaseline::Ideographic:
return AlignmentBaseline::Ideographic;
case DominantBaseline::Alphabetic:
return AlignmentBaseline::Alphabetic;
case DominantBaseline::Hanging:
return AlignmentBaseline::Hanging;
case DominantBaseline::Mathematical:
return AlignmentBaseline::Mathematical;
case DominantBaseline::Central:
return AlignmentBaseline::Central;
case DominantBaseline::Middle:
return AlignmentBaseline::Middle;
case DominantBaseline::TextAfterEdge:
return AlignmentBaseline::TextAfterEdge;
case DominantBaseline::TextBeforeEdge:
return AlignmentBaseline::TextBeforeEdge;
default:
ASSERT_NOT_REACHED();
return AlignmentBaseline::Auto;
}
}
float SVGTextLayoutEngineBaseline::calculateAlignmentBaselineShift(bool isVerticalText, const RenderObject& textRenderer) const
{
const RenderObject* textRendererParent = textRenderer.parent();
ASSERT(textRendererParent);
AlignmentBaseline baseline = textRenderer.style().svgStyle().alignmentBaseline();
if (baseline == AlignmentBaseline::Auto) {
baseline = dominantBaselineToAlignmentBaseline(isVerticalText, textRendererParent);
ASSERT(baseline != AlignmentBaseline::Auto);
}
const FontMetrics& fontMetrics = m_font.fontMetrics();
switch (baseline) {
case AlignmentBaseline::Baseline:
return static_cast<float>(dominantBaselineToAlignmentBaseline(isVerticalText, textRendererParent));
case AlignmentBaseline::BeforeEdge:
case AlignmentBaseline::TextBeforeEdge:
return fontMetrics.floatAscent();
case AlignmentBaseline::Middle:
return fontMetrics.xHeight() / 2;
case AlignmentBaseline::Central:
return (fontMetrics.floatAscent() - fontMetrics.floatDescent()) / 2;
case AlignmentBaseline::AfterEdge:
case AlignmentBaseline::TextAfterEdge:
case AlignmentBaseline::Ideographic:
return fontMetrics.floatDescent();
case AlignmentBaseline::Alphabetic:
return 0;
case AlignmentBaseline::Hanging:
return fontMetrics.floatAscent() * 8 / 10.f;
case AlignmentBaseline::Mathematical:
return fontMetrics.floatAscent() / 2;
case AlignmentBaseline::Auto:
ASSERT_NOT_REACHED();
return 0;
}
ASSERT_NOT_REACHED();
return 0;
}
float SVGTextLayoutEngineBaseline::calculateGlyphOrientationAngle(bool isVerticalText, const SVGRenderStyle& style, const UChar& character) const
{
switch (isVerticalText ? style.glyphOrientationVertical() : style.glyphOrientationHorizontal()) {
case GlyphOrientation::Auto:
switch (static_cast<UEastAsianWidth>(u_getIntPropertyValue(character, UCHAR_EAST_ASIAN_WIDTH))) {
case U_EA_NEUTRAL:
case U_EA_HALFWIDTH:
case U_EA_NARROW:
return 90;
case U_EA_AMBIGUOUS:
case U_EA_FULLWIDTH:
case U_EA_WIDE:
return 0;
case U_EA_COUNT:
ASSERT_NOT_REACHED();
break;
}
ASSERT_NOT_REACHED();
break;
case GlyphOrientation::Degrees90:
return 90;
case GlyphOrientation::Degrees180:
return 180;
case GlyphOrientation::Degrees270:
return 270;
case GlyphOrientation::Degrees0:
return 0;
}
ASSERT_NOT_REACHED();
return 0;
}
static inline bool glyphOrientationIsMultiplyOf180Degrees(float orientationAngle)
{
return !fabsf(fmodf(orientationAngle, 180));
}
float SVGTextLayoutEngineBaseline::calculateGlyphAdvanceAndOrientation(bool isVerticalText, SVGTextMetrics& metrics, float angle, float& xOrientationShift, float& yOrientationShift) const
{
bool orientationIsMultiplyOf180Degrees = glyphOrientationIsMultiplyOf180Degrees(angle);
const FontMetrics& fontMetrics = m_font.fontMetrics();
if (isVerticalText) {
float ascentMinusDescent = fontMetrics.floatAscent() - fontMetrics.floatDescent();
if (!angle) {
xOrientationShift = (ascentMinusDescent - metrics.width()) / 2;
yOrientationShift = fontMetrics.floatAscent();
} else if (angle == 180)
xOrientationShift = (ascentMinusDescent + metrics.width()) / 2;
else if (angle == 270) {
yOrientationShift = metrics.width();
xOrientationShift = ascentMinusDescent;
}
if (angle && !orientationIsMultiplyOf180Degrees)
return metrics.width();
return metrics.height();
}
if (angle == 90)
yOrientationShift = -metrics.width();
else if (angle == 180) {
xOrientationShift = metrics.width();
yOrientationShift = -fontMetrics.floatAscent();
} else if (angle == 270)
xOrientationShift = metrics.width();
if (angle && !orientationIsMultiplyOf180Degrees)
return metrics.height();
return metrics.width();
}
}