author | Robert Longson <longsonr@gmail.com> |
Thu, 22 Mar 2018 18:43:50 +0000 | |
changeset 409497 | 962be3a60013250b9fea1b3ead5e0c9c16b4629b |
parent 409496 | 4cf06e778dcffd807842cc0ec36b1239bcf60202 |
child 409498 | d8480fd61e805a0fd997f8e5320f0de759451eba |
push id | 101223 |
push user | longsonr@gmail.com |
push date | Thu, 22 Mar 2018 18:44:05 +0000 |
treeherder | mozilla-inbound@962be3a60013 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | dholbert |
bugs | 1446650 |
milestone | 61.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/svg/SVGTextPathElement.cpp +++ b/dom/svg/SVGTextPathElement.cpp @@ -43,31 +43,41 @@ nsSVGEnumMapping SVGTextPathElement::sMe }; nsSVGEnumMapping SVGTextPathElement::sSpacingMap[] = { {&nsGkAtoms::_auto, TEXTPATH_SPACINGTYPE_AUTO}, {&nsGkAtoms::exact, TEXTPATH_SPACINGTYPE_EXACT}, {nullptr, 0} }; -nsSVGElement::EnumInfo SVGTextPathElement::sEnumInfo[3] = +nsSVGEnumMapping SVGTextPathElement::sSideMap[] = { + {&nsGkAtoms::left, TEXTPATH_SIDETYPE_LEFT}, + {&nsGkAtoms::right, TEXTPATH_SIDETYPE_RIGHT}, + {nullptr, 0} +}; + +nsSVGElement::EnumInfo SVGTextPathElement::sEnumInfo[4] = { // from SVGTextContentElement: { &nsGkAtoms::lengthAdjust, sLengthAdjustMap, LENGTHADJUST_SPACING }, // from SVGTextPathElement: { &nsGkAtoms::method, sMethodMap, TEXTPATH_METHODTYPE_ALIGN }, { &nsGkAtoms::spacing, sSpacingMap, TEXTPATH_SPACINGTYPE_EXACT + }, + { &nsGkAtoms::side_, + sSideMap, + TEXTPATH_SIDETYPE_LEFT } }; nsSVGElement::StringInfo SVGTextPathElement::sStringInfo[2] = { { &nsGkAtoms::href, kNameSpaceID_None, true }, { &nsGkAtoms::href, kNameSpaceID_XLink, true } }; @@ -108,16 +118,22 @@ SVGTextPathElement::Method() } already_AddRefed<SVGAnimatedEnumeration> SVGTextPathElement::Spacing() { return mEnumAttributes[SPACING].ToDOMAnimatedEnum(this); } +already_AddRefed<SVGAnimatedEnumeration> +SVGTextPathElement::Side() +{ + return mEnumAttributes[SIDE].ToDOMAnimatedEnum(this); +} + //---------------------------------------------------------------------- // nsIContent methods NS_IMETHODIMP_(bool) SVGTextPathElement::IsAttributeMapped(const nsAtom* name) const { static const MappedAttributeEntry* const map[] = { sColorMap,
--- a/dom/svg/SVGTextPathElement.h +++ b/dom/svg/SVGTextPathElement.h @@ -16,16 +16,20 @@ class nsAtom; class nsIContent; nsresult NS_NewSVGTextPathElement(nsIContent **aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo); namespace mozilla { namespace dom { +// textPath side types +static const uint16_t TEXTPATH_SIDETYPE_LEFT = 1; +static const uint16_t TEXTPATH_SIDETYPE_RIGHT = 2; + typedef SVGTextContentElement SVGTextPathElementBase; class SVGTextPathElement final : public SVGTextPathElementBase { friend class ::SVGTextFrame; protected: friend nsresult (::NS_NewSVGTextPathElement(nsIContent **aResult, @@ -39,37 +43,39 @@ public: virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult, bool aPreallocateChildren) const override; // WebIDL already_AddRefed<SVGAnimatedLength> StartOffset(); already_AddRefed<SVGAnimatedEnumeration> Method(); already_AddRefed<SVGAnimatedEnumeration> Spacing(); + already_AddRefed<SVGAnimatedEnumeration> Side(); already_AddRefed<SVGAnimatedString> Href(); protected: virtual LengthAttributesInfo GetLengthInfo() override; virtual EnumAttributesInfo GetEnumInfo() override; virtual StringAttributesInfo GetStringInfo() override; enum { /* TEXTLENGTH, */ STARTOFFSET = 1 }; nsSVGLength2 mLengthAttributes[2]; virtual nsSVGLength2* LengthAttributes() override { return mLengthAttributes; } static LengthInfo sLengthInfo[2]; - enum { /* LENGTHADJUST, */ METHOD = 1, SPACING }; - nsSVGEnum mEnumAttributes[3]; + enum { /* LENGTHADJUST, */ METHOD = 1, SPACING, SIDE }; + nsSVGEnum mEnumAttributes[4]; virtual nsSVGEnum* EnumAttributes() override { return mEnumAttributes; } static nsSVGEnumMapping sMethodMap[]; static nsSVGEnumMapping sSpacingMap[]; - static EnumInfo sEnumInfo[3]; + static nsSVGEnumMapping sSideMap[]; + static EnumInfo sEnumInfo[4]; enum { HREF, XLINK_HREF }; nsSVGString mStringAttributes[2]; static StringInfo sStringInfo[2]; }; } // namespace dom } // namespace mozilla
--- a/layout/reftests/svg/reftest.list +++ b/layout/reftests/svg/reftest.list @@ -472,16 +472,17 @@ fuzzy(16,3) == text-stroke-scaling-02b.h == text-stroke-scaling-02a.html text-stroke-scaling-02b.html == textPath-01.svg textPath-01-ref.svg == textPath-02.svg pass.svg fuzzy-if(skiaContent,1,610) == textPath-03.svg pass.svg == textPath-04.svg pass.svg == textPath-05.html pass.svg == textPath-06.svg pass.svg == textPath-line-01.svg textPath-line-01-ref.svg +== textPath-side-attribute-01.svg pass.svg == text-white-space-01.svg text-white-space-01-ref.svg == thin-stroke-01.svg pass.svg == transform-outer-svg-01.svg transform-outer-svg-01-ref.svg == tspan-dxdy-01.svg tspan-dxdy-ref.svg
new file mode 100644 --- /dev/null +++ b/layout/reftests/svg/textPath-side-attribute-01.svg @@ -0,0 +1,45 @@ +<svg xmlns="http://www.w3.org/2000/svg"> + <defs> + <path id="path1" d="M100 100 h 300"/> + <!-- path2 is drawn in the same place but the opposite direction to path1 + so using it should give the same result as side="right" --> + <path id="path2" d="M400 100 h -300"/> + </defs> + + <rect fill="lime" width="100%" height="100%"/> + + <text font-size="30" fill="red"> + <textPath side="right" href="#path1">Text on a path.</textPath> + </text> + + <text font-size="30" fill="lime" stroke="lime" stroke-width="4"> + <textPath href="#path2">Text on a path.</textPath> + </text> + + <text transform="translate(0, 50)" font-size="30" fill="red"> + <textPath href="#path2">Text on a path.</textPath> + </text> + + <text transform="translate(0, 50)" font-size="30" fill="lime" stroke="lime" stroke-width="4"> + <textPath side="right" href="#path1">Text on a path.</textPath> + </text> + + <text transform="translate(0, 100)" font-size="30" fill="red"> + <textPath href="#path2">Text on a path.</textPath> + </text> + + <text transform="translate(0, 100)" font-size="30" fill="lime" stroke="lime" stroke-width="4"> + <textPath href="#path1">Text on a path. + <set attributeName="side" to="right"/> + </textPath> + </text> + + <text transform="translate(0, 150)" font-size="30" fill="red"> + <textPath href="#path1">Text on a path.</textPath> + </text> + + <text transform="translate(0, 150)" font-size="30" fill="lime" stroke="lime" stroke-width="4"> + <textPath side="left" href="#path1">Text on a path.</textPath> + </text> + +</svg>
--- a/layout/svg/SVGTextFrame.cpp +++ b/layout/svg/SVGTextFrame.cpp @@ -3376,17 +3376,18 @@ SVGTextFrame::MutationObserver::Attribut void SVGTextFrame::HandleAttributeChangeInDescendant(Element* aElement, int32_t aNameSpaceID, nsAtom* aAttribute) { if (aElement->IsSVGElement(nsGkAtoms::textPath)) { if (aNameSpaceID == kNameSpaceID_None && - aAttribute == nsGkAtoms::startOffset) { + (aAttribute == nsGkAtoms::startOffset || + aAttribute == nsGkAtoms::side_)) { NotifyGlyphMetricsChange(); } else if ((aNameSpaceID == kNameSpaceID_XLink || aNameSpaceID == kNameSpaceID_None) && aAttribute == nsGkAtoms::href) { // Blow away our reference, if any nsIFrame* childElementFrame = aElement->GetPrimaryFrame(); if (childElementFrame) { childElementFrame->DeleteProperty( @@ -5087,17 +5088,20 @@ SVGTextFrame::DoTextPathLayout() it.AdvancePastCurrentTextPathFrame(); uint32_t end = it.TextElementCharIndex(); for (uint32_t i = start; i < end; i++) { mPositions[i].mHidden = true; } continue; } - nsIContent* textPath = textPathFrame->GetContent(); + dom::SVGTextPathElement* textPath = + static_cast<dom::SVGTextPathElement*>(textPathFrame->GetContent()); + RefPtr<SVGAnimatedEnumeration> sideEnum = textPath->Side(); + uint16_t side = sideEnum->AnimVal(); gfxFloat offset = GetStartOffset(textPathFrame); Float pathLength = path->ComputeLength(); // Loop for each text frame in the text path. do { uint32_t i = it.TextElementCharIndex(); gfxFloat halfAdvance = @@ -5108,17 +5112,23 @@ SVGTextFrame::DoTextPathLayout() : mPositions[i].mPosition.x) + sign * halfAdvance + offset; // Hide the character if it falls off the end of the path. mPositions[i].mHidden = midx < 0 || midx > pathLength; // Position the character on the path at the right angle. Point tangent; // Unit vector tangent to the point we find. - Point pt = path->ComputePointAtLength(Float(midx), &tangent); + Point pt; + if (side == TEXTPATH_SIDETYPE_RIGHT) { + pt = path->ComputePointAtLength(Float(pathLength - midx), &tangent); + tangent = -tangent; + } else { + pt = path->ComputePointAtLength(Float(midx), &tangent); + } Float rotation = vertical ? atan2f(-tangent.x, tangent.y) : atan2f(tangent.y, tangent.x); Point normal(-tangent.y, tangent.x); // Unit vector normal to the point. Point offsetFromPath = normal * (vertical ? -mPositions[i].mPosition.x : mPositions[i].mPosition.y); pt += offsetFromPath; Point direction = tangent * sign; mPositions[i].mPosition = ThebesPoint(pt) - ThebesPoint(direction) * halfAdvance;