/* static */ nscoord nsMathMLFrame::CalcLength(nsPresContext* aPresContext, nsStyleContext* aStyleContext, const nsCSSValue& aCSSValue, float aFontSizeInflation) { NS_ASSERTION(aCSSValue.IsLengthUnit(), "not a length unit"); if (aCSSValue.IsFixedLengthUnit()) { return aCSSValue.GetFixedLength(aPresContext); } if (aCSSValue.IsPixelLengthUnit()) { return aCSSValue.GetPixelLength(); } nsCSSUnit unit = aCSSValue.GetUnit(); if (eCSSUnit_EM == unit) { const nsStyleFont* font = aStyleContext->StyleFont(); return NSToCoordRound(aCSSValue.GetFloatValue() * (float)font->mFont.size); } else if (eCSSUnit_XHeight == unit) { aPresContext->SetUsesExChUnits(true); RefPtr<nsFontMetrics> fm = nsLayoutUtils:: GetFontMetricsForStyleContext(aStyleContext, aFontSizeInflation); nscoord xHeight = fm->XHeight(); return NSToCoordRound(aCSSValue.GetFloatValue() * (float)xHeight); } // MathML doesn't specify other CSS units such as rem or ch NS_ERROR("Unsupported unit"); return 0; }
/* static */ nscoord nsMathMLFrame::CalcLength(nsPresContext* aPresContext, nsStyleContext* aStyleContext, const nsCSSValue& aCSSValue) { NS_ASSERTION(aCSSValue.IsLengthUnit(), "not a length unit"); if (aCSSValue.IsFixedLengthUnit()) { return aCSSValue.GetLengthTwips(); } nsCSSUnit unit = aCSSValue.GetUnit(); if (eCSSUnit_Pixel == unit) { return NSFloatPixelsToTwips(aCSSValue.GetFloatValue(), aPresContext->ScaledPixelsToTwips()); } else if (eCSSUnit_EM == unit) { const nsStyleFont* font = aStyleContext->GetStyleFont(); return NSToCoordRound(aCSSValue.GetFloatValue() * (float)font->mFont.size); } else if (eCSSUnit_XHeight == unit) { nscoord xHeight; const nsStyleFont* font = aStyleContext->GetStyleFont(); nsCOMPtr<nsIFontMetrics> fm = aPresContext->GetMetricsFor(font->mFont); fm->GetXHeight(xHeight); return NSToCoordRound(aCSSValue.GetFloatValue() * (float)xHeight); } return 0; }
void nsMathMLmpaddedFrame::UpdateValue(int32_t aSign, int32_t aPseudoUnit, const nsCSSValue& aCSSValue, const ReflowOutput& aDesiredSize, nscoord& aValueToUpdate, float aFontSizeInflation) const { nsCSSUnit unit = aCSSValue.GetUnit(); if (NS_MATHML_SIGN_INVALID != aSign && eCSSUnit_Null != unit) { nscoord scaler = 0, amount = 0; if (eCSSUnit_Percent == unit || eCSSUnit_Number == unit) { switch(aPseudoUnit) { case NS_MATHML_PSEUDO_UNIT_WIDTH: scaler = aDesiredSize.Width(); break; case NS_MATHML_PSEUDO_UNIT_HEIGHT: scaler = aDesiredSize.BlockStartAscent(); break; case NS_MATHML_PSEUDO_UNIT_DEPTH: scaler = aDesiredSize.Height() - aDesiredSize.BlockStartAscent(); break; default: // if we ever reach here, it would mean something is wrong // somewhere with the setup and/or the caller NS_ERROR("Unexpected Pseudo Unit"); return; } } if (eCSSUnit_Number == unit) amount = NSToCoordRound(float(scaler) * aCSSValue.GetFloatValue()); else if (eCSSUnit_Percent == unit) amount = NSToCoordRound(float(scaler) * aCSSValue.GetPercentValue()); else amount = CalcLength(PresContext(), mStyleContext, aCSSValue, aFontSizeInflation); if (NS_MATHML_SIGN_PLUS == aSign) aValueToUpdate += amount; else if (NS_MATHML_SIGN_MINUS == aSign) aValueToUpdate -= amount; else aValueToUpdate = amount; } }
void nsMathMLmpaddedFrame::UpdateValue(PRInt32 aSign, PRInt32 aPseudoUnit, const nsCSSValue& aCSSValue, const nsBoundingMetrics& aBoundingMetrics, nscoord& aValueToUpdate) const { nsCSSUnit unit = aCSSValue.GetUnit(); if (NS_MATHML_SIGN_INVALID != aSign && eCSSUnit_Null != unit) { nscoord scaler = 0, amount = 0; if (eCSSUnit_Percent == unit || eCSSUnit_Number == unit) { switch(aPseudoUnit) { case NS_MATHML_PSEUDO_UNIT_WIDTH: scaler = aBoundingMetrics.width; break; case NS_MATHML_PSEUDO_UNIT_HEIGHT: scaler = aBoundingMetrics.ascent; break; case NS_MATHML_PSEUDO_UNIT_DEPTH: scaler = aBoundingMetrics.descent; break; default: // if we ever reach here, it would mean something is wrong // somewhere with the setup and/or the caller NS_ERROR("Unexpected Pseudo Unit"); return; } } if (eCSSUnit_Number == unit) amount = NSToCoordRound(float(scaler) * aCSSValue.GetFloatValue()); else if (eCSSUnit_Percent == unit) amount = NSToCoordRound(float(scaler) * aCSSValue.GetPercentValue()); else amount = CalcLength(PresContext(), mStyleContext, aCSSValue); nscoord oldValue = aValueToUpdate; if (NS_MATHML_SIGN_PLUS == aSign) aValueToUpdate += amount; else if (NS_MATHML_SIGN_MINUS == aSign) aValueToUpdate -= amount; else aValueToUpdate = amount; } }
/* Helper function to fill in an nscoord with the specified nsCSSValue. */ static nscoord CalcLength(const nsCSSValue &aValue, nsStyleContext* aContext, nsPresContext* aPresContext, PRBool &aCanStoreInRuleTree) { if (aValue.GetUnit() == eCSSUnit_Pixel) { // Handle this here (even though nsRuleNode::CalcLength handles it // fine) so that callers are allowed to pass a null style context // and pres context to SetToTransformFunction if they know (as // nsStyleAnimation does) that all lengths within the transform // function have already been computed to pixels and percents. return nsPresContext::CSSPixelsToAppUnits(aValue.GetFloatValue()); } return nsRuleNode::CalcLength(aValue, aContext, aPresContext, aCanStoreInRuleTree); }
float ProcessTranslatePart(const nsCSSValue& aValue, nsStyleContext* aContext, nsPresContext* aPresContext, RuleNodeCacheConditions& aConditions, TransformReferenceBox* aRefBox, TransformReferenceBox::DimensionGetter aDimensionGetter) { nscoord offset = 0; float percent = 0.0f; if (aValue.GetUnit() == eCSSUnit_Percent) { percent = aValue.GetPercentValue(); } else if (aValue.GetUnit() == eCSSUnit_Pixel || aValue.GetUnit() == eCSSUnit_Number) { // Handle this here (even though nsRuleNode::CalcLength handles it // fine) so that callers are allowed to pass a null style context // and pres context to SetToTransformFunction if they know (as // StyleAnimationValue does) that all lengths within the transform // function have already been computed to pixels and percents. // // Raw numbers are treated as being pixels. // // Don't convert to aValue to AppUnits here to avoid precision issues. return aValue.GetFloatValue(); } else if (aValue.IsCalcUnit()) { nsRuleNode::ComputedCalc result = nsRuleNode::SpecifiedCalcToComputedCalc(aValue, aContext, aPresContext, aConditions); percent = result.mPercent; offset = result.mLength; } else { offset = nsRuleNode::CalcLength(aValue, aContext, aPresContext, aConditions); } float translation = NSAppUnitsToFloatPixels(offset, nsPresContext::AppUnitsPerCSSPixel()); // We want to avoid calling aDimensionGetter if there's no percentage to be // resolved (for performance reasons - see TransformReferenceBox). if (percent != 0.0f && aRefBox) { translation += percent * NSAppUnitsToFloatPixels((aRefBox->*aDimensionGetter)(), nsPresContext::AppUnitsPerCSSPixel()); } return translation; }
float ProcessTranslatePart(const nsCSSValue& aValue, nsStyleContext* aContext, nsPresContext* aPresContext, bool& aCanStoreInRuleTree, nscoord aSize) { nscoord offset = 0; float percent = 0.0f; if (aValue.GetUnit() == eCSSUnit_Percent) { percent = aValue.GetPercentValue(); } else if (aValue.GetUnit() == eCSSUnit_Pixel || aValue.GetUnit() == eCSSUnit_Number) { // Handle this here (even though nsRuleNode::CalcLength handles it // fine) so that callers are allowed to pass a null style context // and pres context to SetToTransformFunction if they know (as // StyleAnimationValue does) that all lengths within the transform // function have already been computed to pixels and percents. // // Raw numbers are treated as being pixels. // // Don't convert to aValue to AppUnits here to avoid precision issues. return aValue.GetFloatValue(); } else if (aValue.IsCalcUnit()) { nsRuleNode::ComputedCalc result = nsRuleNode::SpecifiedCalcToComputedCalc(aValue, aContext, aPresContext, aCanStoreInRuleTree); percent = result.mPercent; offset = result.mLength; } else { offset = nsRuleNode::CalcLength(aValue, aContext, aPresContext, aCanStoreInRuleTree); } return (percent * NSAppUnitsToFloatPixels(aSize, nsPresContext::AppUnitsPerCSSPixel())) + NSAppUnitsToFloatPixels(offset, nsPresContext::AppUnitsPerCSSPixel()); }
// parse an input string in the following format (see bug 148326 for testcases): // [+|-] unsigned-number (% [pseudo-unit] | pseudo-unit | css-unit | namedspace) bool nsMathMLmpaddedFrame::ParseAttribute(nsString& aString, int32_t& aSign, nsCSSValue& aCSSValue, int32_t& aPseudoUnit) { aCSSValue.Reset(); aSign = NS_MATHML_SIGN_INVALID; aPseudoUnit = NS_MATHML_PSEUDO_UNIT_UNSPECIFIED; aString.CompressWhitespace(); // aString is not a const in this code int32_t stringLength = aString.Length(); if (!stringLength) return false; nsAutoString number, unit; ////////////////////// // see if the sign is there int32_t i = 0; if (aString[0] == '+') { aSign = NS_MATHML_SIGN_PLUS; i++; } else if (aString[0] == '-') { aSign = NS_MATHML_SIGN_MINUS; i++; } else aSign = NS_MATHML_SIGN_UNSPECIFIED; // get the number bool gotDot = false, gotPercent = false; for (; i < stringLength; i++) { PRUnichar c = aString[i]; if (gotDot && c == '.') { // error - two dots encountered aSign = NS_MATHML_SIGN_INVALID; return false; } if (c == '.') gotDot = true; else if (!nsCRT::IsAsciiDigit(c)) { break; } number.Append(c); } // catch error if we didn't enter the loop above... we could simply initialize // floatValue = 1, to cater for cases such as width="height", but that wouldn't // be in line with the spec which requires an explicit number if (number.IsEmpty()) { aSign = NS_MATHML_SIGN_INVALID; return false; } nsresult errorCode; float floatValue = number.ToFloat(&errorCode); if (NS_FAILED(errorCode)) { aSign = NS_MATHML_SIGN_INVALID; return false; } // see if this is a percentage-based value if (i < stringLength && aString[i] == '%') { i++; gotPercent = true; } // the remainder now should be a css-unit, or a pseudo-unit, or a named-space aString.Right(unit, stringLength - i); if (unit.IsEmpty()) { if (gotPercent) { // case ["+"|"-"] unsigned-number "%" aCSSValue.SetPercentValue(floatValue / 100.0f); aPseudoUnit = NS_MATHML_PSEUDO_UNIT_ITSELF; return true; } else { // case ["+"|"-"] unsigned-number // XXXfredw: should we allow non-zero unitless values? See bug 757703. if (!floatValue) { aCSSValue.SetFloatValue(floatValue, eCSSUnit_Number); aPseudoUnit = NS_MATHML_PSEUDO_UNIT_ITSELF; return true; } } } else if (unit.EqualsLiteral("width")) aPseudoUnit = NS_MATHML_PSEUDO_UNIT_WIDTH; else if (unit.EqualsLiteral("height")) aPseudoUnit = NS_MATHML_PSEUDO_UNIT_HEIGHT; else if (unit.EqualsLiteral("depth")) aPseudoUnit = NS_MATHML_PSEUDO_UNIT_DEPTH; else if (!gotPercent) { // percentage can only apply to a pseudo-unit // see if the unit is a named-space if (nsMathMLElement::ParseNamedSpaceValue(unit, aCSSValue, nsMathMLElement:: PARSE_ALLOW_NEGATIVE)) { // re-scale properly, and we know that the unit of the named-space is 'em' floatValue *= aCSSValue.GetFloatValue(); aCSSValue.SetFloatValue(floatValue, eCSSUnit_EM); aPseudoUnit = NS_MATHML_PSEUDO_UNIT_NAMEDSPACE; return true; } // see if the input was just a CSS value // We are not supposed to have a unitless, percent, negative or namedspace // value here. number.Append(unit); // leave the sign out if it was there if (nsMathMLElement::ParseNumericValue(number, aCSSValue, nsMathMLElement:: PARSE_SUPPRESS_WARNINGS, nullptr)) return true; } // if we enter here, we have a number that will act as a multiplier on a pseudo-unit if (aPseudoUnit != NS_MATHML_PSEUDO_UNIT_UNSPECIFIED) { if (gotPercent) aCSSValue.SetPercentValue(floatValue / 100.0f); else aCSSValue.SetFloatValue(floatValue, eCSSUnit_Number); return true; } #ifdef DEBUG printf("mpadded: attribute with bad numeric value: %s\n", NS_LossyConvertUTF16toASCII(aString).get()); #endif // if we reach here, it means we encounter an unexpected input aSign = NS_MATHML_SIGN_INVALID; return false; }
void nsMathMLmpaddedFrame::UpdateValue(PRInt32 aSign, PRInt32 aPseudoUnit, const nsCSSValue& aCSSValue, nscoord aLeftSpace, const nsBoundingMetrics& aBoundingMetrics, nscoord& aValueToUpdate) const { nsCSSUnit unit = aCSSValue.GetUnit(); if (NS_MATHML_SIGN_INVALID != aSign && eCSSUnit_Null != unit) { nscoord scaler = 0, amount = 0; if (eCSSUnit_Percent == unit || eCSSUnit_Number == unit) { switch(aPseudoUnit) { case NS_MATHML_PSEUDO_UNIT_WIDTH: scaler = aBoundingMetrics.width; break; case NS_MATHML_PSEUDO_UNIT_HEIGHT: scaler = aBoundingMetrics.ascent; break; case NS_MATHML_PSEUDO_UNIT_DEPTH: scaler = aBoundingMetrics.descent; break; case NS_MATHML_PSEUDO_UNIT_LSPACE: scaler = aLeftSpace; break; default: // if we ever reach here, it would mean something is wrong // somewhere with the setup and/or the caller NS_ASSERTION(0, "Unexpected Pseudo Unit"); return; } } if (eCSSUnit_Number == unit) amount = NSToCoordRound(float(scaler) * aCSSValue.GetFloatValue()); else if (eCSSUnit_Percent == unit) amount = NSToCoordRound(float(scaler) * aCSSValue.GetPercentValue()); else amount = CalcLength(PresContext(), mStyleContext, aCSSValue); nscoord oldValue = aValueToUpdate; if (NS_MATHML_SIGN_PLUS == aSign) aValueToUpdate += amount; else if (NS_MATHML_SIGN_MINUS == aSign) aValueToUpdate -= amount; else aValueToUpdate = amount; /* The REC says: Dimensions that would be positive if the content was rendered normally cannot be made negative using <mpadded>; a positive dimension is set to 0 if it would otherwise become negative. Dimensions which are initially 0 can be made negative */ if (0 < oldValue && 0 > aValueToUpdate) aValueToUpdate = 0; } }
// parse an input string in the following format (see bug 148326 for testcases): // [+|-] unsigned-number (% [pseudo-unit] | pseudo-unit | css-unit | namedspace) PRBool nsMathMLmpaddedFrame::ParseAttribute(nsString& aString, PRInt32& aSign, nsCSSValue& aCSSValue, PRInt32& aPseudoUnit) { aCSSValue.Reset(); aSign = NS_MATHML_SIGN_INVALID; aPseudoUnit = NS_MATHML_PSEUDO_UNIT_UNSPECIFIED; aString.CompressWhitespace(); // aString is not a const in this code PRInt32 stringLength = aString.Length(); if (!stringLength) return PR_FALSE; nsAutoString number, unit; ////////////////////// // see if the sign is there PRInt32 i = 0; if (aString[0] == '+') { aSign = NS_MATHML_SIGN_PLUS; i++; } else if (aString[0] == '-') { aSign = NS_MATHML_SIGN_MINUS; i++; } else aSign = NS_MATHML_SIGN_UNSPECIFIED; // skip any space after the sign if (i < stringLength && nsCRT::IsAsciiSpace(aString[i])) i++; // get the number PRBool gotDot = PR_FALSE, gotPercent = PR_FALSE; for (; i < stringLength; i++) { PRUnichar c = aString[i]; if (gotDot && c == '.') { // error - two dots encountered aSign = NS_MATHML_SIGN_INVALID; return PR_FALSE; } if (c == '.') gotDot = PR_TRUE; else if (!nsCRT::IsAsciiDigit(c)) { break; } number.Append(c); } // catch error if we didn't enter the loop above... we could simply initialize // floatValue = 1, to cater for cases such as width="height", but that wouldn't // be in line with the spec which requires an explicit number if (number.IsEmpty()) { #ifdef NS_DEBUG printf("mpadded: attribute with bad numeric value: %s\n", NS_LossyConvertUTF16toASCII(aString).get()); #endif aSign = NS_MATHML_SIGN_INVALID; return PR_FALSE; } PRInt32 errorCode; float floatValue = number.ToFloat(&errorCode); if (errorCode) { aSign = NS_MATHML_SIGN_INVALID; return PR_FALSE; } // skip any space after the number if (i < stringLength && nsCRT::IsAsciiSpace(aString[i])) i++; // see if this is a percentage-based value if (i < stringLength && aString[i] == '%') { i++; gotPercent = PR_TRUE; // skip any space after the '%' sign if (i < stringLength && nsCRT::IsAsciiSpace(aString[i])) i++; } // the remainder now should be a css-unit, or a pseudo-unit, or a named-space aString.Right(unit, stringLength - i); if (unit.IsEmpty()) { // also cater for the edge case of "0" for which the unit is optional if (gotPercent || !floatValue) { aCSSValue.SetPercentValue(floatValue / 100.0f); aPseudoUnit = NS_MATHML_PSEUDO_UNIT_ITSELF; return PR_TRUE; } /* else { // no explicit CSS unit and no explicit pseudo-unit... // In this case, the MathML REC suggests taking ems for // h-unit (width, lspace) or exs for v-unit (height, depth). // Here, however, we explicitly request authors to specify // the unit. This is more in line with the CSS REC (and // it allows keeping the code simpler...) } */ } else if (unit.EqualsLiteral("width")) aPseudoUnit = NS_MATHML_PSEUDO_UNIT_WIDTH; else if (unit.EqualsLiteral("height")) aPseudoUnit = NS_MATHML_PSEUDO_UNIT_HEIGHT; else if (unit.EqualsLiteral("depth")) aPseudoUnit = NS_MATHML_PSEUDO_UNIT_DEPTH; else if (unit.EqualsLiteral("lspace")) aPseudoUnit = NS_MATHML_PSEUDO_UNIT_LSPACE; else if (!gotPercent) { // percentage can only apply to a pseudo-unit // see if the unit is a named-space // XXX nsnull in ParseNamedSpacedValue()? don't access mstyle? if (ParseNamedSpaceValue(nsnull, unit, aCSSValue)) { // re-scale properly, and we know that the unit of the named-space is 'em' floatValue *= aCSSValue.GetFloatValue(); aCSSValue.SetFloatValue(floatValue, eCSSUnit_EM); aPseudoUnit = NS_MATHML_PSEUDO_UNIT_NAMEDSPACE; return PR_TRUE; } // see if the input was just a CSS value number.Append(unit); // leave the sign out if it was there if (ParseNumericValue(number, aCSSValue)) return PR_TRUE; } // if we enter here, we have a number that will act as a multiplier on a pseudo-unit if (aPseudoUnit != NS_MATHML_PSEUDO_UNIT_UNSPECIFIED) { if (gotPercent) aCSSValue.SetPercentValue(floatValue / 100.0f); else aCSSValue.SetFloatValue(floatValue, eCSSUnit_Number); return PR_TRUE; } #ifdef NS_DEBUG printf("mpadded: attribute with bad numeric value: %s\n", NS_LossyConvertUTF16toASCII(aString).get()); #endif // if we reach here, it means we encounter an unexpected input aSign = NS_MATHML_SIGN_INVALID; return PR_FALSE; }