nsresult SVGTransformListParser::MatchScale() { GetNextToken(); float s[2]; PRUint32 count; ENSURE_MATCHED(MatchNumberArguments(s, NS_ARRAY_LENGTH(s), &count)); switch (count) { case 1: s[1] = s[0]; // fall-through case 2: { SVGTransform* transform = mTransforms.AppendElement(); NS_ENSURE_TRUE(transform, NS_ERROR_OUT_OF_MEMORY); transform->SetScale(s[0], s[1]); break; } default: return NS_ERROR_FAILURE; } return NS_OK; }
already_AddRefed<SVGTransform> DOMSVGTransformList::ReplaceItem(SVGTransform& newItem, uint32_t index, ErrorResult& error) { if (IsAnimValList()) { error.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); return nullptr; } if (index >= LengthNoFlush()) { error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); return nullptr; } nsRefPtr<SVGTransform> domItem = &newItem; if (newItem.HasOwner()) { domItem = newItem.Clone(); // must do this before changing anything! } AutoChangeTransformListNotifier notifier(this); if (mItems[index]) { // Notify any existing DOM item of removal *before* modifying the lists so // that the DOM item can copy the *old* value at its index: mItems[index]->RemovingFromList(); } InternalList()[index] = domItem->ToSVGTransform(); mItems[index] = domItem; // This MUST come after the ToSVGPoint() call, otherwise that call // would end up reading bad data from InternalList()! domItem->InsertingIntoList(this, index, IsAnimValList()); return domItem.forget(); }
nsresult SVGTransformListParser::MatchRotate() { GetNextToken(); float r[3]; PRUint32 count; ENSURE_MATCHED(MatchNumberArguments(r, NS_ARRAY_LENGTH(r), &count)); switch (count) { case 1: r[1] = r[2] = 0.f; // fall-through case 3: { SVGTransform* transform = mTransforms.AppendElement(); NS_ENSURE_TRUE(transform, NS_ERROR_OUT_OF_MEMORY); transform->SetRotate(r[0], r[1], r[2]); break; } default: return NS_ERROR_FAILURE; } return NS_OK; }
nsresult SVGTransformListParser::MatchTranslate() { GetNextToken(); float t[2]; uint32_t count; ENSURE_MATCHED(MatchNumberArguments(t, ArrayLength(t), &count)); switch (count) { case 1: t[1] = 0.f; // fall-through case 2: { SVGTransform* transform = mTransforms.AppendElement(); NS_ENSURE_TRUE(transform, NS_ERROR_OUT_OF_MEMORY); transform->SetTranslate(t[0], t[1]); break; } default: return NS_ERROR_FAILURE; } return NS_OK; }
String SVGTransformList::valueAsString() const { // TODO: We may want to build a real transform string, instead of concatting to a matrix(...). SVGTransform transform = concatenate(); if (transform.type() == SVGTransform::SVG_TRANSFORM_MATRIX) { TransformationMatrix matrix = transform.matrix(); return String::format("matrix(%f %f %f %f %f %f)", matrix.a(), matrix.b(), matrix.c(), matrix.d(), matrix.e(), matrix.f()); } return String(); }
already_AddRefed<SVGTransform> DOMSVGTransformList::Initialize(SVGTransform& newItem, ErrorResult& error) { if (IsAnimValList()) { error.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); return nullptr; } // If newItem is already in a list we should insert a clone of newItem, and // for consistency, this should happen even if *this* is the list that // newItem is currently in. Note that in the case of newItem being in this // list, the Clear() call before the InsertItemBefore() call would remove it // from this list, and so the InsertItemBefore() call would not insert a // clone of newItem, it would actually insert newItem. To prevent that from // happening we have to do the clone here, if necessary. nsRefPtr<SVGTransform> domItem = &newItem; if (domItem->HasOwner()) { domItem = newItem.Clone(); } Clear(error); MOZ_ASSERT(!error.Failed(), "How could this fail?"); return InsertItemBefore(*domItem, 0, error); }
already_AddRefed<SVGTransform> DOMSVGTransformList::InsertItemBefore(SVGTransform& newItem, uint32_t index, ErrorResult& error) { if (IsAnimValList()) { error.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); return nullptr; } index = std::min(index, LengthNoFlush()); if (index >= SVGTransform::MaxListIndex()) { error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); return nullptr; } nsRefPtr<SVGTransform> domItem = &newItem; if (newItem.HasOwner()) { domItem = newItem.Clone(); // must do this before changing anything! } // Ensure we have enough memory so we can avoid complex error handling below: if (!mItems.SetCapacity(mItems.Length() + 1) || !InternalList().SetCapacity(InternalList().Length() + 1)) { error.Throw(NS_ERROR_OUT_OF_MEMORY); return nullptr; } nsAttrValue emptyOrOldValue = Element()->WillChangeTransformList(); // Now that we know we're inserting, keep animVal list in sync as necessary. MaybeInsertNullInAnimValListAt(index); InternalList().InsertItem(index, domItem->ToSVGTransform()); mItems.InsertElementAt(index, domItem.get()); // This MUST come after the insertion into InternalList(), or else under the // insertion into InternalList() the values read from domItem would be bad // data from InternalList() itself!: domItem->InsertingIntoList(this, index, IsAnimValList()); UpdateListIndicesFromIndex(mItems, index + 1); Element()->DidChangeTransformList(emptyOrOldValue); if (mAList->IsAnimating()) { Element()->AnimationNeedsResample(); } return domItem.forget(); }
nsresult SVGTransformListParser::MatchMatrix() { GetNextToken(); float m[6]; PRUint32 count; ENSURE_MATCHED(MatchNumberArguments(m, NS_ARRAY_LENGTH(m), &count)); if (count != 6) { return NS_ERROR_FAILURE; } SVGTransform* transform = mTransforms.AppendElement(); NS_ENSURE_TRUE(transform, NS_ERROR_OUT_OF_MEMORY); transform->SetMatrix(gfxMatrix(m[0], m[1], m[2], m[3], m[4], m[5])); return NS_OK; }
nsresult SVGTransformListParser::MatchSkewY() { GetNextToken(); float skew; PRUint32 count; ENSURE_MATCHED(MatchNumberArguments(&skew, 1, &count)); if (count != 1) { return NS_ERROR_FAILURE; } SVGTransform* transform = mTransforms.AppendElement(); NS_ENSURE_TRUE(transform, NS_ERROR_OUT_OF_MEMORY); transform->SetSkewY(skew); return NS_OK; }
bool SVGTransformable::parseTransformValue(SVGTransform::SVGTransformType type, const UChar*& ptr, const UChar* end, SVGTransform& transform) { if (type == SVGTransform::SVG_TRANSFORM_UNKNOWN) return false; int valueCount = 0; float values[] = {0, 0, 0, 0, 0, 0}; if ((valueCount = parseTransformParamList(ptr, end, values, requiredValuesForType[type], optionalValuesForType[type])) < 0) return false; switch (type) { case SVGTransform::SVG_TRANSFORM_UNKNOWN: ASSERT_NOT_REACHED(); break; case SVGTransform::SVG_TRANSFORM_SKEWX: transform.setSkewX(values[0]); break; case SVGTransform::SVG_TRANSFORM_SKEWY: transform.setSkewY(values[0]); break; case SVGTransform::SVG_TRANSFORM_SCALE: if (valueCount == 1) // Spec: if only one param given, assume uniform scaling transform.setScale(values[0], values[0]); else transform.setScale(values[0], values[1]); break; case SVGTransform::SVG_TRANSFORM_TRANSLATE: if (valueCount == 1) // Spec: if only one param given, assume 2nd param to be 0 transform.setTranslate(values[0], 0); else transform.setTranslate(values[0], values[1]); break; case SVGTransform::SVG_TRANSFORM_ROTATE: if (valueCount == 1) transform.setRotate(values[0], 0, 0); else transform.setRotate(values[0], values[1], values[2]); break; case SVGTransform::SVG_TRANSFORM_MATRIX: transform.setMatrix(AffineTransform(values[0], values[1], values[2], values[3], values[4], values[5])); break; } return true; }
SVGTransform SVGTransformDistance::addToSVGTransform(const SVGTransform& transform) const { ASSERT(m_type == transform.type() || transform == SVGTransform()); SVGTransform newTransform(transform); switch (m_type) { case SVGTransform::SVG_TRANSFORM_UNKNOWN: return SVGTransform(); case SVGTransform::SVG_TRANSFORM_MATRIX: return SVGTransform(transform.matrix() * m_transform); case SVGTransform::SVG_TRANSFORM_TRANSLATE: { FloatPoint translation = transform.translate(); translation += FloatSize::narrowPrecision(m_transform.e(), m_transform.f()); newTransform.setTranslate(translation.x(), translation.y()); return newTransform; } case SVGTransform::SVG_TRANSFORM_SCALE: { FloatSize scale = transform.scale(); scale += FloatSize::narrowPrecision(m_transform.a(), m_transform.d()); newTransform.setScale(scale.width(), scale.height()); return newTransform; } case SVGTransform::SVG_TRANSFORM_ROTATE: { // FIXME: I'm not certain the translation is calculated correctly here FloatPoint center = transform.rotationCenter(); newTransform.setRotate(transform.angle() + m_angle, center.x() + m_cx, center.y() + m_cy); return newTransform; } case SVGTransform::SVG_TRANSFORM_SKEWX: newTransform.setSkewX(transform.angle() + m_angle); return newTransform; case SVGTransform::SVG_TRANSFORM_SKEWY: newTransform.setSkewY(transform.angle() + m_angle); return newTransform; } ASSERT_NOT_REACHED(); return SVGTransform(); }
SVGTransform* SVGTransformDistance::addSVGTransforms(SVGTransform* first, SVGTransform* second, unsigned repeatCount) { ASSERT(first->transformType() == second->transformType()); SVGTransform* transform = SVGTransform::create(); switch (first->transformType()) { case kSvgTransformMatrix: ASSERT_NOT_REACHED(); case kSvgTransformUnknown: return transform; case kSvgTransformRotate: { transform->setRotate(first->angle() + second->angle() * repeatCount, first->rotationCenter().x() + second->rotationCenter().x() * repeatCount, first->rotationCenter().y() + second->rotationCenter().y() * repeatCount); return transform; } case kSvgTransformTranslate: { float dx = first->translate().x() + second->translate().x() * repeatCount; float dy = first->translate().y() + second->translate().y() * repeatCount; transform->setTranslate(dx, dy); return transform; } case kSvgTransformScale: { FloatSize scale = second->scale(); scale.scale(repeatCount); scale += first->scale(); transform->setScale(scale.width(), scale.height()); return transform; } case kSvgTransformSkewx: transform->setSkewX(first->angle() + second->angle() * repeatCount); return transform; case kSvgTransformSkewy: transform->setSkewY(first->angle() + second->angle() * repeatCount); return transform; } ASSERT_NOT_REACHED(); return transform; }
SVGTransform* SVGTransformDistance::addToSVGTransform( SVGTransform* transform) const { DCHECK(m_transformType == transform->transformType() || m_transformType == kSvgTransformUnknown); SVGTransform* newTransform = transform->clone(); switch (m_transformType) { case kSvgTransformMatrix: ASSERT_NOT_REACHED(); case kSvgTransformUnknown: return SVGTransform::create(); case kSvgTransformTranslate: { FloatPoint translation = transform->translate(); translation += FloatSize::narrowPrecision(m_transform.e(), m_transform.f()); newTransform->setTranslate(translation.x(), translation.y()); return newTransform; } case kSvgTransformScale: { FloatSize scale = transform->scale(); scale += FloatSize::narrowPrecision(m_transform.a(), m_transform.d()); newTransform->setScale(scale.width(), scale.height()); return newTransform; } case kSvgTransformRotate: { FloatPoint center = transform->rotationCenter(); newTransform->setRotate(transform->angle() + m_angle, center.x() + m_cx, center.y() + m_cy); return newTransform; } case kSvgTransformSkewx: newTransform->setSkewX(transform->angle() + m_angle); return newTransform; case kSvgTransformSkewy: newTransform->setSkewY(transform->angle() + m_angle); return newTransform; } ASSERT_NOT_REACHED(); return newTransform; }
SVGTransform *SVGSVGElement::createSVGTransformFromMatrix(SVGMatrix *matrix) { SVGTransform *obj = SVGSVGElement::createSVGTransform(); obj->setMatrix(matrix); return obj; }
bool SVGTransformable::parseTransformAttribute(SVGTransformList* list, const AtomicString& transform) { double x[] = {0, 0, 0, 0, 0, 0}; int nr = 0, required = 0, optional = 0; const UChar* currTransform = transform.characters(); const UChar* end = currTransform + transform.length(); bool delimParsed = false; while (currTransform < end) { delimParsed = false; unsigned short type = SVGTransform::SVG_TRANSFORM_UNKNOWN; skipOptionalSpaces(currTransform, end); if (currTransform >= end) return false; if (*currTransform == 's') { if (skipString(currTransform, end, skewXDesc, sizeof(skewXDesc) / sizeof(UChar))) { required = 1; optional = 0; type = SVGTransform::SVG_TRANSFORM_SKEWX; } else if (skipString(currTransform, end, skewYDesc, sizeof(skewYDesc) / sizeof(UChar))) { required = 1; optional = 0; type = SVGTransform::SVG_TRANSFORM_SKEWY; } else if (skipString(currTransform, end, scaleDesc, sizeof(scaleDesc) / sizeof(UChar))) { required = 1; optional = 1; type = SVGTransform::SVG_TRANSFORM_SCALE; } else return false; } else if (skipString(currTransform, end, translateDesc, sizeof(translateDesc) / sizeof(UChar))) { required = 1; optional = 1; type = SVGTransform::SVG_TRANSFORM_TRANSLATE; } else if (skipString(currTransform, end, rotateDesc, sizeof(rotateDesc) / sizeof(UChar))) { required = 1; optional = 2; type = SVGTransform::SVG_TRANSFORM_ROTATE; } else if (skipString(currTransform, end, matrixDesc, sizeof(matrixDesc) / sizeof(UChar))) { required = 6; optional = 0; type = SVGTransform::SVG_TRANSFORM_MATRIX; } else return false; if ((nr = parseTransformParamList(currTransform, end, x, required, optional)) < 0) return false; SVGTransform t; switch (type) { case SVGTransform::SVG_TRANSFORM_SKEWX: t.setSkewX(narrowPrecisionToFloat(x[0])); break; case SVGTransform::SVG_TRANSFORM_SKEWY: t.setSkewY(narrowPrecisionToFloat(x[0])); break; case SVGTransform::SVG_TRANSFORM_SCALE: if (nr == 1) // Spec: if only one param given, assume uniform scaling t.setScale(narrowPrecisionToFloat(x[0]), narrowPrecisionToFloat(x[0])); else t.setScale(narrowPrecisionToFloat(x[0]), narrowPrecisionToFloat(x[1])); break; case SVGTransform::SVG_TRANSFORM_TRANSLATE: if (nr == 1) // Spec: if only one param given, assume 2nd param to be 0 t.setTranslate(narrowPrecisionToFloat(x[0]), 0); else t.setTranslate(narrowPrecisionToFloat(x[0]), narrowPrecisionToFloat(x[1])); break; case SVGTransform::SVG_TRANSFORM_ROTATE: if (nr == 1) t.setRotate(narrowPrecisionToFloat(x[0]), 0, 0); else t.setRotate(narrowPrecisionToFloat(x[0]), narrowPrecisionToFloat(x[1]), narrowPrecisionToFloat(x[2])); break; case SVGTransform::SVG_TRANSFORM_MATRIX: t.setMatrix(AffineTransform(x[0], x[1], x[2], x[3], x[4], x[5])); break; } ExceptionCode ec = 0; list->appendItem(t, ec); skipOptionalSpaces(currTransform, end); if (currTransform < end && *currTransform == ',') { delimParsed = true; currTransform++; } skipOptionalSpaces(currTransform, end); } return !delimParsed; }
float SVGAnimateTransformElement::calculateDistance(const String& fromString, const String& toString) { // FIXME: This is not correct in all cases. The spec demands that each component (translate x and y for example) // is paced separately. To implement this we need to treat each component as individual animation everywhere. SVGTransform from = parseTransformValue(fromString); if (!from.isValid()) return -1.f; SVGTransform to = parseTransformValue(toString); if (!to.isValid() || from.type() != to.type()) return -1.f; if (to.type() == SVGTransform::SVG_TRANSFORM_TRANSLATE) { FloatSize diff = to.translate() - from.translate(); return sqrtf(diff.width() * diff.width() + diff.height() * diff.height()); } if (to.type() == SVGTransform::SVG_TRANSFORM_ROTATE) return fabsf(to.angle() - from.angle()); if (to.type() == SVGTransform::SVG_TRANSFORM_SCALE) { FloatSize diff = to.scale() - from.scale(); return sqrtf(diff.width() * diff.width() + diff.height() * diff.height()); } return -1.f; }
SVGTransformDistance::SVGTransformDistance(const SVGTransform& fromSVGTransform, const SVGTransform& toSVGTransform) : m_type(fromSVGTransform.type()) , m_angle(0) , m_cx(0) , m_cy(0) { ASSERT(m_type == toSVGTransform.type()); switch (m_type) { case SVGTransform::SVG_TRANSFORM_UNKNOWN: return; case SVGTransform::SVG_TRANSFORM_MATRIX: // FIXME: need to be able to subtract to matrices return; case SVGTransform::SVG_TRANSFORM_ROTATE: { FloatSize centerDistance = toSVGTransform.rotationCenter() - fromSVGTransform.rotationCenter(); m_angle = toSVGTransform.angle() - fromSVGTransform.angle(); m_cx = centerDistance.width(); m_cy = centerDistance.height(); return; } case SVGTransform::SVG_TRANSFORM_TRANSLATE: { FloatSize translationDistance = toSVGTransform.translate() - fromSVGTransform.translate(); m_transform.translate(translationDistance.width(), translationDistance.height()); return; } case SVGTransform::SVG_TRANSFORM_SCALE: { float scaleX = toSVGTransform.scale().width() - fromSVGTransform.scale().width(); float scaleY = toSVGTransform.scale().height() - fromSVGTransform.scale().height(); m_transform.scaleNonUniform(scaleX, scaleY); return; } case SVGTransform::SVG_TRANSFORM_SKEWX: case SVGTransform::SVG_TRANSFORM_SKEWY: m_angle = toSVGTransform.angle() - fromSVGTransform.angle(); return; } }
void SVGTransformDistance::addSVGTransform(const SVGTransform& transform, bool absoluteValue) { // If this is the first add, set the type for this SVGTransformDistance if (m_type == SVGTransform::SVG_TRANSFORM_UNKNOWN) m_type = transform.type(); ASSERT(m_type == transform.type()); switch (m_type) { case SVGTransform::SVG_TRANSFORM_UNKNOWN: return; case SVGTransform::SVG_TRANSFORM_MATRIX: m_transform *= transform.matrix(); // FIXME: what does 'distance' between two transforms mean? how should we respect 'absoluteValue' here? return; case SVGTransform::SVG_TRANSFORM_ROTATE: m_angle += absoluteValue ? fabsf(transform.angle()) : transform.angle(); m_cx += absoluteValue ? fabsf(transform.rotationCenter().x()) : transform.rotationCenter().x(); m_cy += absoluteValue ? fabsf(transform.rotationCenter().y()) : transform.rotationCenter().y(); // fall through case SVGTransform::SVG_TRANSFORM_TRANSLATE: { float dx = absoluteValue ? fabsf(transform.translate().x()) : transform.translate().x(); float dy = absoluteValue ? fabsf(transform.translate().y()) : transform.translate().y(); m_transform.translate(dx, dy); return; } case SVGTransform::SVG_TRANSFORM_SCALE: { float scaleX = absoluteValue ? fabsf(transform.scale().width()) : transform.scale().width(); float scaleY = absoluteValue ? fabsf(transform.scale().height()) : transform.scale().height(); m_transform.scaleNonUniform(scaleX, scaleY); return; } case SVGTransform::SVG_TRANSFORM_SKEWX: case SVGTransform::SVG_TRANSFORM_SKEWY: m_angle += absoluteValue ? fabsf(transform.angle()) : transform.angle(); return; } ASSERT_NOT_REACHED(); return; }
SVGTransform SVGTransformDistance::addSVGTransforms(const SVGTransform& first, const SVGTransform& second) { ASSERT(first.type() == second.type()); SVGTransform transform; switch (first.type()) { case SVGTransform::SVG_TRANSFORM_UNKNOWN: return SVGTransform(); case SVGTransform::SVG_TRANSFORM_ROTATE: { transform.setRotate(first.angle() + second.angle(), first.rotationCenter().x() + second.rotationCenter().x(), first.rotationCenter().y() + second.rotationCenter().y()); return transform; } case SVGTransform::SVG_TRANSFORM_MATRIX: transform.setMatrix(first.matrix() * second.matrix()); return transform; case SVGTransform::SVG_TRANSFORM_TRANSLATE: { float dx = first.translate().x() + second.translate().x(); float dy = first.translate().y() + second.translate().y(); transform.setTranslate(dx, dy); return transform; } case SVGTransform::SVG_TRANSFORM_SCALE: { FloatSize scale = first.scale() + second.scale(); transform.setScale(scale.width(), scale.height()); return transform; } case SVGTransform::SVG_TRANSFORM_SKEWX: transform.setSkewX(first.angle() + second.angle()); return transform; case SVGTransform::SVG_TRANSFORM_SKEWY: transform.setSkewY(first.angle() + second.angle()); return transform; } ASSERT_NOT_REACHED(); return SVGTransform(); }
void SVGTransformList::ParseTransform(StringIn s) { if (s.IsEmpty()) return; ASSERT(0); #if 0 const WCHAR* p = s->c_str(); if (p == NULL) THROW(std::exception("null pointer")); while (*p) { while (*p && std::isspace(*p)) p++; // Skip spaces // Get type const WCHAR* transformType = p; int transformTypeLength = 0; while (*p && std::isalpha(*p)) { transformTypeLength++; p++; } while (*p && std::isspace(*p)) p++; // Skip spaces // Get string inside ( ) if (*p++ != L'(') break; // Error const WCHAR* start = p; while (*p && *p != L')') { p++; } System::StringW* param_string = new System::StringW(string_copy(start, p - start)); if (*p++ != L')') break; // Error while (*p && std::isspace(*p)) p++; // Skip spaces SVGTransform* transform = NULL; #if WIN32 if (!_wcsnicmp(transformType, L"translate", transformTypeLength)) { double x, y; GetTranslateValues(param_string->c_str(), x, y); transform = new SVGTransformMutable; transform->SetTranslate(x, y); } else if (!_wcsnicmp(transformType, L"rotate", transformTypeLength)) { double deg, cx, cy; GetRotateValues(param_string->c_str(), deg, cx, cy); transform = new SVGTransformMutable; transform->SetRotate(deg, cx, cy); } else if (!_wcsnicmp(transformType, L"scale", transformTypeLength)) { double sx, sy; GetScaleValues(param_string->c_str(), sx, sy); transform = new SVGTransformMutable; transform->SetScale(sx, sy); } else if (!_wcsnicmp(transformType, L"skewX", transformTypeLength)) { double deg; GetSkewValues(param_string->c_str(), deg); transform = new SVGTransformMutable; transform->SetSkewX(deg); } else if (!_wcsnicmp(transformType, L"skewY", transformTypeLength)) { double deg; GetSkewValues(param_string->c_str(), deg); transform = new SVGTransformMutable; transform->SetSkewY(deg); } else if (!_wcsnicmp(transformType, L"matrix", transformTypeLength)) { transform = new SVGTransformMutable; transform->m_type = SVG_TRANSFORM_MATRIX; GetMatrixValues(param_string->c_str(), transform->m_matrix); } #else ASSERT(0); #endif if (transform != NULL) { transform->m_owner = this; // transform->m_pListener = this; m_p->m_items.Add(transform); } if (*p == ',') p++; while (*p && std::isspace(*p)) p++; // Skip spaces } #endif }
String SVGTransformList::StringFromTransformList() const { IO::StringWriter str; unsigned int numberOfItems = m_p->m_items.GetSize(); for (size_t i = 0; i < numberOfItems; i++) { SVGTransform* transform = m_p->m_items[i]; SVGTransformType type = transform->get_type(); SVGMatrix* matrix = transform->get_matrix(); double a = matrix->get_a(); double b = matrix->get_b(); double c = matrix->get_c(); double d = matrix->get_d(); double e = matrix->get_e(); double f = matrix->get_f(); if (i > 0) str << " "; switch (type) { case SVG_TRANSFORM_TRANSLATE: { str << "translate(" << e << "," << f << ")"; } break; case SVG_TRANSFORM_SCALE: { // swprintf(str2, OLESTR("scale(%g, %g)"), a, d); // str += str2; str << "scale(" << a << "," << d << ")"; } break; case SVG_TRANSFORM_ROTATE: { double angle = transform->get_angle(); // swprintf(str2, OLESTR("rotate(%g, %g, %g)"), angle, e, f); // str += str2; str << "rotate(" << angle << "," << e << "," << f << ")"; } break; case SVG_TRANSFORM_SKEWX: { double angle = transform->get_angle(); // swprintf(str2, OLESTR("skewX(%g)"), angle); // str += str2; str << "skewX(" << angle << ")"; } break; case SVG_TRANSFORM_SKEWY: { double angle = transform->get_angle(); // swprintf(str2, OLESTR("skewY(%g)"), angle); // str += str2; str << "skewY(" << angle << ")"; } break; case SVG_TRANSFORM_MATRIX: { // swprintf(str2, OLESTR("matrix(%g %g %g %g %g %g)"), a, b, c, d, e, f); // str += str2; str << "matrix(" << a << "," << b << "," << c << "," << d << "," << e << "," << f << ")"; } break; default: ASSERT(0); } } return str.str(); }
SVGTransformDistance::SVGTransformDistance(const SVGTransform& fromSVGTransform, const SVGTransform& toSVGTransform) : m_type(fromSVGTransform.type()) , m_angle(0) , m_cx(0) , m_cy(0) { ASSERT(m_type == toSVGTransform.type()); switch (m_type) { case SVGTransform::SVG_TRANSFORM_MATRIX: ASSERT_NOT_REACHED(); case SVGTransform::SVG_TRANSFORM_UNKNOWN: break; case SVGTransform::SVG_TRANSFORM_ROTATE: { FloatSize centerDistance = toSVGTransform.rotationCenter() - fromSVGTransform.rotationCenter(); m_angle = toSVGTransform.angle() - fromSVGTransform.angle(); m_cx = centerDistance.width(); m_cy = centerDistance.height(); break; } case SVGTransform::SVG_TRANSFORM_TRANSLATE: { FloatSize translationDistance = toSVGTransform.translate() - fromSVGTransform.translate(); m_transform.translate(translationDistance.width(), translationDistance.height()); break; } case SVGTransform::SVG_TRANSFORM_SCALE: { float scaleX = toSVGTransform.scale().width() - fromSVGTransform.scale().width(); float scaleY = toSVGTransform.scale().height() - fromSVGTransform.scale().height(); m_transform.scaleNonUniform(scaleX, scaleY); break; } case SVGTransform::SVG_TRANSFORM_SKEWX: case SVGTransform::SVG_TRANSFORM_SKEWY: m_angle = toSVGTransform.angle() - fromSVGTransform.angle(); break; } }