static inline float dimensionForViewportUnit(const SVGElement* context, CSSPrimitiveValue::UnitType unit) { if (!context) return 0; const Document& document = context->document(); FrameView* view = document.view(); if (!view) return 0; const ComputedStyle* style = computedStyleForLengthResolving(context); if (!style) return 0; FloatSize viewportSize(view->width(), view->height()); switch (unit) { case CSSPrimitiveValue::UnitType::ViewportWidth: return viewportLengthPercent(viewportSize.width()) / style->effectiveZoom(); case CSSPrimitiveValue::UnitType::ViewportHeight: return viewportLengthPercent(viewportSize.height()) / style->effectiveZoom(); case CSSPrimitiveValue::UnitType::ViewportMin: return viewportMinPercent(viewportSize) / style->effectiveZoom(); case CSSPrimitiveValue::UnitType::ViewportMax: return viewportMaxPercent(viewportSize) / style->effectiveZoom(); default: break; } ASSERT_NOT_REACHED(); return 0; }
float SVGLengthContext::convertValueToUserUnits(float value, SVGLengthMode mode, CSSPrimitiveValue::UnitType fromUnit) const { float userUnits = value; switch (fromUnit) { case CSSPrimitiveValue::UnitType::Pixels: case CSSPrimitiveValue::UnitType::Number: case CSSPrimitiveValue::UnitType::UserUnits: userUnits = value; break; case CSSPrimitiveValue::UnitType::Percentage: { FloatSize viewportSize; if (!determineViewport(viewportSize)) return 0; userUnits = value * dimensionForLengthMode(mode, viewportSize) / 100; break; } case CSSPrimitiveValue::UnitType::Ems: userUnits = convertValueFromEMSToUserUnits(computedStyleForLengthResolving(m_context), value); break; case CSSPrimitiveValue::UnitType::Exs: userUnits = convertValueFromEXSToUserUnits(value); break; case CSSPrimitiveValue::UnitType::Centimeters: userUnits = value * cssPixelsPerCentimeter; break; case CSSPrimitiveValue::UnitType::Millimeters: userUnits = value * cssPixelsPerMillimeter; break; case CSSPrimitiveValue::UnitType::Inches: userUnits = value * cssPixelsPerInch; break; case CSSPrimitiveValue::UnitType::Points: userUnits = value * cssPixelsPerPoint; break; case CSSPrimitiveValue::UnitType::Picas: userUnits = value * cssPixelsPerPica; break; case CSSPrimitiveValue::UnitType::Rems: userUnits = convertValueFromEMSToUserUnits(rootElementStyle(m_context), value); break; case CSSPrimitiveValue::UnitType::Chs: userUnits = convertValueFromCHSToUserUnits(value); break; case CSSPrimitiveValue::UnitType::ViewportWidth: case CSSPrimitiveValue::UnitType::ViewportHeight: case CSSPrimitiveValue::UnitType::ViewportMin: case CSSPrimitiveValue::UnitType::ViewportMax: userUnits = value * dimensionForViewportUnit(m_context, fromUnit); break; default: ASSERT_NOT_REACHED(); break; } // Since we mix css <length> values with svg's length values we need to // clamp values to the narrowest range, otherwise it can result in // rendering issues. return CSSPrimitiveValue::clampToCSSLengthRange(userUnits); }
float SVGLengthContext::convertValueFromCHSToUserUnits(float value) const { const ComputedStyle* style = computedStyleForLengthResolving(m_context); if (!style) return 0; return value * style->fontMetrics().zeroWidth() / style->effectiveZoom(); }
float SVGLengthContext::convertValueFromEXSToUserUnits(float value) const { const ComputedStyle* style = computedStyleForLengthResolving(m_context); if (!style) return 0; // Use of ceil allows a pixel match to the W3Cs expected output of coords-units-03-b.svg // if this causes problems in real world cases maybe it would be best to remove this return value * ceilf(style->fontMetrics().xHeight() / style->effectiveZoom()); }
float SVGLengthContext::convertValueToUserUnits(float value, SVGLengthMode mode, SVGLengthType fromUnit) const { float userUnits = value; switch (fromUnit) { case LengthTypeUnknown: return 0; case LengthTypePX: case LengthTypeNumber: userUnits = value; break; case LengthTypePercentage: { FloatSize viewportSize; if (!determineViewport(viewportSize)) return 0; userUnits = value * dimensionForLengthMode(mode, viewportSize) / 100; break; } case LengthTypeEMS: userUnits = convertValueFromEMSToUserUnits(computedStyleForLengthResolving(m_context), value); break; case LengthTypeEXS: userUnits = convertValueFromEXSToUserUnits(value); break; case LengthTypeCM: userUnits = value * cssPixelsPerCentimeter; break; case LengthTypeMM: userUnits = value * cssPixelsPerMillimeter; break; case LengthTypeIN: userUnits = value * cssPixelsPerInch; break; case LengthTypePT: userUnits = value * cssPixelsPerPoint; break; case LengthTypePC: userUnits = value * cssPixelsPerPica; break; case LengthTypeREMS: userUnits = convertValueFromEMSToUserUnits(rootElementStyle(m_context), value); break; case LengthTypeCHS: userUnits = convertValueFromCHSToUserUnits(value); break; default: ASSERT_NOT_REACHED(); break; } // Since we mix css <length> values with svg's length values we need to // clamp values to the narrowest range, otherwise it can result in // rendering issues. return CSSPrimitiveValue::clampToCSSLengthRange(userUnits); }
float SVGLengthContext::convertValueFromUserUnitsToCHS(float value) const { const ComputedStyle* style = computedStyleForLengthResolving(m_context); if (!style) return 0; float zeroWidth = style->fontMetrics().zeroWidth(); if (!zeroWidth) return 0; return value / zeroWidth; }
float SVGLengthContext::convertValueFromUserUnits( float value, SVGLengthMode mode, CSSPrimitiveValue::UnitType toUnit) const { switch (toUnit) { case CSSPrimitiveValue::UnitType::Pixels: case CSSPrimitiveValue::UnitType::Number: case CSSPrimitiveValue::UnitType::Integer: case CSSPrimitiveValue::UnitType::UserUnits: return value; case CSSPrimitiveValue::UnitType::Percentage: { FloatSize viewportSize; if (!determineViewport(viewportSize)) return 0; float dimension = dimensionForLengthMode(mode, viewportSize); if (!dimension) return 0; // LengthTypePercentage is represented with 100% = 100.0. // Good for accuracy but could eventually be changed. return value * 100 / dimension; } case CSSPrimitiveValue::UnitType::Ems: return convertValueFromUserUnitsToEMS( computedStyleForLengthResolving(m_context), value); case CSSPrimitiveValue::UnitType::Exs: return convertValueFromUserUnitsToEXS(value); case CSSPrimitiveValue::UnitType::Rems: return convertValueFromUserUnitsToEMS(rootElementStyle(m_context), value); case CSSPrimitiveValue::UnitType::Chs: return convertValueFromUserUnitsToCHS(value); case CSSPrimitiveValue::UnitType::Centimeters: return value / cssPixelsPerCentimeter; case CSSPrimitiveValue::UnitType::Millimeters: return value / cssPixelsPerMillimeter; case CSSPrimitiveValue::UnitType::Inches: return value / cssPixelsPerInch; case CSSPrimitiveValue::UnitType::Points: return value / cssPixelsPerPoint; case CSSPrimitiveValue::UnitType::Picas: return value / cssPixelsPerPica; case CSSPrimitiveValue::UnitType::ViewportWidth: case CSSPrimitiveValue::UnitType::ViewportHeight: case CSSPrimitiveValue::UnitType::ViewportMin: case CSSPrimitiveValue::UnitType::ViewportMax: return value / dimensionForViewportUnit(m_context, toUnit); default: break; } ASSERT_NOT_REACHED(); return 0; }
float SVGLengthContext::convertValueFromUserUnitsToCHS(float value) const { const ComputedStyle* style = computedStyleForLengthResolving(m_context); const SimpleFontData* fontData = style->font().primaryFont(); if (!style || !fontData) return 0; float zeroWidth = fontData->getFontMetrics().zeroWidth() / style->effectiveZoom(); if (!zeroWidth) return 0; return value / zeroWidth; }
float SVGLengthContext::resolveValue(const CSSPrimitiveValue& primitiveValue, SVGLengthMode mode) const { const ComputedStyle* style = computedStyleForLengthResolving(m_context); if (!style) return 0; const ComputedStyle* rootStyle = rootElementStyle(m_context); if (!rootStyle) return 0; CSSToLengthConversionData conversionData = CSSToLengthConversionData( style, rootStyle, m_context->document().layoutViewItem(), 1.0f); Length length = primitiveValue.convertToLength(conversionData); return valueForLength(length, 1.0f, mode); }
float SVGLengthContext::convertValueFromUserUnitsToEXS(float value) const { const ComputedStyle* style = computedStyleForLengthResolving(m_context); const SimpleFontData* fontData = style->font().primaryFont(); if (!style || !fontData) return 0; // Use of ceil allows a pixel match to the W3Cs expected output of // coords-units-03-b.svg, if this causes problems in real world cases maybe it // would be best to remove this. float xHeight = ceilf(fontData->getFontMetrics().xHeight() / style->effectiveZoom()); if (!xHeight) return 0; return value / xHeight; }
float SVGLengthContext::convertValueFromUserUnits(float value, SVGLengthMode mode, SVGLengthType toUnit) const { switch (toUnit) { case LengthTypeUnknown: return 0; case LengthTypeNumber: return value; case LengthTypePercentage: { FloatSize viewportSize; if (!determineViewport(viewportSize)) return 0; float dimension = dimensionForLengthMode(mode, viewportSize); if (!dimension) return 0; // LengthTypePercentage is represented with 100% = 100.0. // Good for accuracy but could eventually be changed. return value * 100 / dimension; } case LengthTypeEMS: return convertValueFromUserUnitsToEMS(computedStyleForLengthResolving(m_context), value); case LengthTypeEXS: return convertValueFromUserUnitsToEXS(value); case LengthTypeREMS: return convertValueFromUserUnitsToEMS(rootElementStyle(m_context), value); case LengthTypeCHS: return convertValueFromUserUnitsToCHS(value); case LengthTypePX: return value; case LengthTypeCM: return value / cssPixelsPerCentimeter; case LengthTypeMM: return value / cssPixelsPerMillimeter; case LengthTypeIN: return value / cssPixelsPerInch; case LengthTypePT: return value / cssPixelsPerPoint; case LengthTypePC: return value / cssPixelsPerPica; } ASSERT_NOT_REACHED(); return 0; }