String Color::serializedAsCSSComponentValue() const { StringBuilder result; result.reserveCapacity(32); bool colorHasAlpha = hasAlpha(); if (colorHasAlpha) result.appendLiteral("rgba("); else result.appendLiteral("rgb("); result.appendNumber(static_cast<unsigned char>(red())); result.appendLiteral(", "); result.appendNumber(static_cast<unsigned char>(green())); result.appendLiteral(", "); result.appendNumber(static_cast<unsigned char>(blue())); if (colorHasAlpha) { result.appendLiteral(", "); NumberToStringBuffer buffer; const char* alphaString = numberToFixedPrecisionString(alpha() / 255.0f, 6, buffer, true); result.append(alphaString, strlen(alphaString)); } result.append(')'); return result.toString(); }
TEST(DtoaTest, TestNumberToFixedPrecisionString_DontTruncateTrailingZeros) { NumberToStringBuffer buffer; // There should be a trailing decimal and zeros. numberToFixedPrecisionString(0.0, 6, buffer, false); EXPECT_STREQ("0.00000", buffer); }
TEST(DtoaTest, TestNumberToFixedPrecisionString) { NumberToStringBuffer buffer; // There should be no trailing decimal or zeros. numberToFixedPrecisionString(0.0, 6, buffer, true); EXPECT_STREQ("0", buffer); // Up to 6 leading zeros. numberToFixedPrecisionString(0.00000123123123, 6, buffer, true); EXPECT_STREQ("0.00000123123", buffer); numberToFixedPrecisionString(0.000000123123123, 6, buffer, true); EXPECT_STREQ("1.23123e-7", buffer); // Up to 6 places before the decimal. numberToFixedPrecisionString(123123.123, 6, buffer, true); EXPECT_STREQ("123123", buffer); numberToFixedPrecisionString(1231231.23, 6, buffer, true); EXPECT_STREQ("1.23123e+6", buffer); // Don't strip trailing zeros in exponents. // http://crbug.com/545711 numberToFixedPrecisionString(0.000000000123123, 6, buffer, true); EXPECT_STREQ("1.23123e-10", buffer); // FIXME: Trailing zeros before exponents should be stripped. numberToFixedPrecisionString(0.0000000001, 6, buffer, true); EXPECT_STREQ("1.00000e-10", buffer); }
// toPrecision converts a number to a string, takeing an argument specifying a // number of significant figures to round the significand to. For positive // exponent, all values that can be represented using a decimal fraction will // be, e.g. when rounding to 3 s.f. any value up to 999 will be formated as a // decimal, whilst 1000 is converted to the exponential representation 1.00e+3. // For negative exponents values >= 1e-6 are formated as decimal fractions, // with smaller values converted to exponential representation. EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec) { double x; if (!toThisNumber(exec->thisValue(), x)) return throwVMTypeError(exec); // Get the argument. int significantFigures; bool isUndefined; if (!getIntegerArgumentInRange(exec, 1, 21, significantFigures, isUndefined)) return throwVMError(exec, createRangeError(exec, ASCIILiteral("toPrecision() argument must be between 1 and 21"))); // To precision called with no argument is treated as ToString. if (isUndefined) return JSValue::encode(jsString(exec, String::numberToStringECMAScript(x))); // Handle NaN and Infinity. if (!std::isfinite(x)) return JSValue::encode(jsNontrivialString(exec, String::numberToStringECMAScript(x))); NumberToStringBuffer buffer; return JSValue::encode(jsString(exec, String(numberToFixedPrecisionString(x, significantFigures, buffer)))); }
String String::number(double number, unsigned precision, TrailingZerosTruncatingPolicy trailingZerosTruncatingPolicy) { NumberToStringBuffer buffer; return String(numberToFixedPrecisionString(number, precision, buffer, trailingZerosTruncatingPolicy == TruncateTrailingZeros)); }
ALWAYS_INLINE String CSSPrimitiveValue::formatNumberForcustomCSSText() const { switch (m_primitiveUnitType) { case CSS_UNKNOWN: return String(); case CSS_NUMBER: case CSS_PARSER_INTEGER: return formatNumberValue(""); case CSS_PERCENTAGE: return formatNumberValue("%"); case CSS_EMS: return formatNumberValue("em"); case CSS_EXS: return formatNumberValue("ex"); case CSS_REMS: return formatNumberValue("rem"); case CSS_CHS: return formatNumberValue("ch"); case CSS_PX: return formatNumberValue("px"); case CSS_CM: return formatNumberValue("cm"); #if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY) case CSS_DPPX: return formatNumberValue("dppx"); case CSS_DPI: return formatNumberValue("dpi"); case CSS_DPCM: return formatNumberValue("dpcm"); #endif case CSS_MM: return formatNumberValue("mm"); case CSS_IN: return formatNumberValue("in"); case CSS_PT: return formatNumberValue("pt"); case CSS_PC: return formatNumberValue("pc"); case CSS_DEG: return formatNumberValue("deg"); case CSS_RAD: return formatNumberValue("rad"); case CSS_GRAD: return formatNumberValue("grad"); case CSS_MS: return formatNumberValue("ms"); case CSS_S: return formatNumberValue("s"); case CSS_HZ: return formatNumberValue("hz"); case CSS_KHZ: return formatNumberValue("khz"); case CSS_TURN: return formatNumberValue("turn"); case CSS_FR: return formatNumberValue("fr"); case CSS_DIMENSION: // FIXME: We currently don't handle CSS_DIMENSION properly as we don't store // the actual dimension, just the numeric value as a string. case CSS_STRING: return quoteCSSStringIfNeeded(m_value.string); case CSS_URI: return "url(" + quoteCSSURLIfNeeded(m_value.string) + ')'; case CSS_VALUE_ID: return valueName(m_value.valueID); case CSS_PROPERTY_ID: return propertyName(m_value.propertyID); case CSS_ATTR: { StringBuilder result; result.reserveCapacity(6 + m_value.string->length()); result.appendLiteral("attr("); result.append(m_value.string); result.append(')'); return result.toString(); } case CSS_COUNTER_NAME: return "counter(" + String(m_value.string) + ')'; case CSS_COUNTER: { StringBuilder result; String separator = m_value.counter->separator(); if (separator.isEmpty()) result.appendLiteral("counter("); else result.appendLiteral("counters("); result.append(m_value.counter->identifier()); if (!separator.isEmpty()) { result.appendLiteral(", "); result.append(quoteCSSStringIfNeeded(separator)); } String listStyle = m_value.counter->listStyle(); if (!listStyle.isEmpty()) { result.appendLiteral(", "); result.append(listStyle); } result.append(')'); return result.toString(); } case CSS_RECT: return getRectValue()->cssText(); case CSS_QUAD: return getQuadValue()->cssText(); case CSS_RGBCOLOR: case CSS_PARSER_HEXCOLOR: { RGBA32 rgbColor = m_value.rgbcolor; if (m_primitiveUnitType == CSS_PARSER_HEXCOLOR) Color::parseHexColor(m_value.string, rgbColor); Color color(rgbColor); Vector<LChar> result; result.reserveInitialCapacity(32); bool colorHasAlpha = color.hasAlpha(); if (colorHasAlpha) result.append("rgba(", 5); else result.append("rgb(", 4); appendNumber(result, static_cast<unsigned char>(color.red())); result.append(", ", 2); appendNumber(result, static_cast<unsigned char>(color.green())); result.append(", ", 2); appendNumber(result, static_cast<unsigned char>(color.blue())); if (colorHasAlpha) { result.append(", ", 2); NumberToStringBuffer buffer; const char* alphaString = numberToFixedPrecisionString(color.alpha() / 255.0f, 6, buffer, true); result.append(alphaString, strlen(alphaString)); } result.append(')'); return String::adopt(result); } case CSS_PAIR: return getPairValue()->cssText(); #if ENABLE(DASHBOARD_SUPPORT) case CSS_DASHBOARD_REGION: { StringBuilder result; for (DashboardRegion* region = getDashboardRegionValue(); region; region = region->m_next.get()) { if (!result.isEmpty()) result.append(' '); result.appendLiteral("dashboard-region("); result.append(region->m_label); if (region->m_isCircle) result.appendLiteral(" circle"); else if (region->m_isRectangle) result.appendLiteral(" rectangle"); else break; if (region->top()->m_primitiveUnitType == CSS_VALUE_ID && region->top()->getValueID() == CSSValueInvalid) { ASSERT(region->right()->m_primitiveUnitType == CSS_VALUE_ID); ASSERT(region->bottom()->m_primitiveUnitType == CSS_VALUE_ID); ASSERT(region->left()->m_primitiveUnitType == CSS_VALUE_ID); ASSERT(region->right()->getValueID() == CSSValueInvalid); ASSERT(region->bottom()->getValueID() == CSSValueInvalid); ASSERT(region->left()->getValueID() == CSSValueInvalid); } else { result.append(' '); result.append(region->top()->cssText()); result.append(' '); result.append(region->right()->cssText()); result.append(' '); result.append(region->bottom()->cssText()); result.append(' '); result.append(region->left()->cssText()); } result.append(')'); } return result.toString(); } #endif case CSS_PARSER_OPERATOR: { char c = static_cast<char>(m_value.parserOperator); return String(&c, 1U); } case CSS_PARSER_IDENTIFIER: return quoteCSSStringIfNeeded(m_value.string); case CSS_CALC: return m_value.calc->cssText(); case CSS_SHAPE: return m_value.shape->cssText(); case CSS_VW: return formatNumberValue("vw"); case CSS_VH: return formatNumberValue("vh"); case CSS_VMIN: return formatNumberValue("vmin"); case CSS_VMAX: return formatNumberValue("vmax"); } return String(); }