/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
class CharIterator; class DisplaySVGText; class SVGTextFrame; class TextFrameIterator; class TextNodeCorrespondenceRecorder; struct TextRenderedRun; class TextRenderedRunIterator;
namespace dom { struct DOMPointInit; class DOMSVGPoint; class SVGRect; class SVGGeometryElement;
} // namespace dom
} // namespace mozilla
/** * Information about the positioning for a single character in an SVG <text> * element. * * During SVG text layout, we use infinity values to represent positions and * rotations that are not explicitly specified with x/y/rotate attributes.
*/ struct CharPosition {
CharPosition()
: mAngle(0),
mHidden(false),
mUnaddressable(false),
mClusterOrLigatureGroupMiddle(false),
mRunBoundary(false),
mStartOfChunk(false) {}
/** * A runnable to mark glyph positions as needing to be recomputed * and to invalid the bounds of the SVGTextFrame frame.
*/ class GlyphMetricsUpdater : public Runnable { public:
NS_DECL_NSIRUNNABLE explicit GlyphMetricsUpdater(SVGTextFrame* aFrame)
: Runnable("GlyphMetricsUpdater"), mFrame(aFrame) {} staticvoid Run(SVGTextFrame* aFrame); void Revoke() { mFrame = nullptr; }
private:
SVGTextFrame* mFrame;
};
/** * Frame class for SVG <text> elements. * * An SVGTextFrame manages SVG text layout, painting and interaction for * all descendent text content elements. The frame tree will look like this: * * SVGTextFrame -- for <text> * <anonymous block frame> * ns{Block,Inline,Text}Frames -- for text nodes, <tspan>s, <a>s, etc. * * SVG text layout is done by: * * 1. Reflowing the anonymous block frame. * 2. Inspecting the (app unit) positions of the glyph for each character in * the nsTextFrames underneath the anonymous block frame. * 3. Determining the (user unit) positions for each character in the <text> * using the x/y/dx/dy/rotate attributes on all the text content elements, * and using the step 2 results to fill in any gaps. * 4. Applying any other SVG specific text layout (anchoring and text paths) * to the positions computed in step 3. * * Rendering of the text is done by splitting up each nsTextFrame into ranges * that can be contiguously painted. (For example <text x="10 20">abcd</text> * would have two contiguous ranges: one for the "a" and one for the "bcd".) * Each range is called a "text rendered run", represented by a TextRenderedRun * object. The TextRenderedRunIterator class performs that splitting and * returns a TextRenderedRun for each bit of text to be painted separately. * * Each rendered run is painted by calling nsTextFrame::PaintText. If the text * formatting is simple enough (solid fill, no stroking, etc.), PaintText will * itself do the painting. Otherwise, a DrawPathCallback is passed to * PaintText so that we can fill the text geometry with SVG paint servers.
*/ class SVGTextFrame final : public SVGDisplayContainerFrame { friend nsIFrame* ::NS_NewSVGTextFrame(mozilla::PresShell* aPresShell,
ComputedStyle* aStyle);
/** * Finds the nsTextFrame for the closest rendered run to the specified point.
*/ void FindCloserFrameForSelection( const nsPoint& aPoint, FrameWithDistance* aCurrentBestFrame) override;
// SVG DOM text methods:
uint32_t GetNumberOfChars(nsIContent* aContent); float GetComputedTextLength(nsIContent* aContent);
MOZ_CAN_RUN_SCRIPT_BOUNDARY void SelectSubString(nsIContent* aContent,
uint32_t charnum,
uint32_t nchars,
ErrorResult& aRv); bool RequiresSlowFallbackForSubStringLength(); float GetSubStringLengthFastPath(nsIContent* aContent, uint32_t charnum,
uint32_t nchars, ErrorResult& aRv); /** * This fallback version of GetSubStringLength takes * into account glyph positioning and requires us to have flushed layout * before calling it. As per the SVG 2 spec, typically glyph * positioning does not affect the results of getSubStringLength, but one * exception is text in a textPath where we need to ignore characters that * fall off the end of the textPath path.
*/ float GetSubStringLengthSlowFallback(nsIContent* aContent, uint32_t charnum,
uint32_t nchars, ErrorResult& aRv);
/** * Handles a base or animated attribute value change to a descendant * text content element.
*/ void HandleAttributeChangeInDescendant(dom::Element* aElement,
int32_t aNameSpaceID,
nsAtom* aAttribute);
/** * Calls ScheduleReflowSVGNonDisplayText if this is a non-display frame, * and SVGUtils::ScheduleReflowSVG otherwise.
*/ void ScheduleReflowSVG();
/** * Reflows the anonymous block frame of this non-display SVGTextFrame. * * When we are under SVGDisplayContainerFrame::ReflowSVG, we need to * reflow any SVGTextFrame frames in the subtree in case they are * being observed (by being for example in a <mask>) and the change * that caused the reflow would not already have caused a reflow. * * Note that displayed SVGTextFrames are reflowed as needed, when PaintSVG * is called or some SVG DOM method is called on the element.
*/ void ReflowSVGNonDisplayText();
/** * This is a function that behaves similarly to SVGUtils::ScheduleReflowSVG, * but which will skip over any ancestor non-display container frames on the * way to the SVGOuterSVGFrame. It exists for the situation where a * non-display <text> element has changed and needs to ensure ReflowSVG will * be called on its closest display container frame, so that * SVGDisplayContainerFrame::ReflowSVG will call ReflowSVGNonDisplayText on * it. * * We have to do this in two cases: in response to a style change on a * non-display <text>, where aReason will be * IntrinsicDirty::FrameAncestorsAndDescendants (the common case), and also in * response to glyphs changes on non-display <text> (i.e., animated * SVG-in-OpenType glyphs), in which case aReason will be None, since layout * doesn't need to be recomputed.
*/ void ScheduleReflowSVGNonDisplayText(IntrinsicDirty aReason);
/** * Updates the mFontSizeScaleFactor value by looking at the range of * font-sizes used within the <text>. * * @return Whether mFontSizeScaleFactor changed.
*/ bool UpdateFontSizeScaleFactor();
double GetFontSizeScaleFactor() const;
/** * Takes a point from the <text> element's user space and * converts it to the appropriate frame user space of aChildFrame, * according to which rendered run the point hits.
*/
Point TransformFramePointToTextChild(const Point& aPoint, const nsIFrame* aChildFrame);
/** * Takes an app unit rectangle in the coordinate space of a given descendant * frame of this frame, and returns a rectangle in the <text> element's user * space that covers all parts of rendered runs that intersect with the * rectangle.
*/
gfxRect TransformFrameRectFromTextChild(const nsRect& aRect, const nsIFrame* aChildFrame);
/** As above, but taking and returning a device px rect. */
Rect TransformFrameRectFromTextChild(const Rect& aRect, const nsIFrame* aChildFrame);
/** As above, but with a single point */
Point TransformFramePointFromTextChild(const Point& aPoint, const nsIFrame* aChildFrame);
private: /** * Mutation observer used to watch for text positioning attribute changes * on descendent text content elements (like <tspan>s).
*/ class MutationObserver final : public nsStubMutationObserver { public: explicit MutationObserver(SVGTextFrame* aFrame) : mFrame(aFrame) {
MOZ_ASSERT(mFrame, "MutationObserver needs a non-null frame");
mFrame->GetContent()->AddMutationObserver(this);
SetEnabledCallbacks(kCharacterDataChanged | kAttributeChanged |
kContentAppended | kContentInserted |
kContentWillBeRemoved);
}
/** * Resolves Bidi for the anonymous block child if it needs it.
*/ void MaybeResolveBidiForAnonymousBlockChild();
/** * Reflows the anonymous block child if it is dirty or has dirty * children, or if the SVGTextFrame itself is dirty.
*/ void MaybeReflowAnonymousBlockChild();
/** * Performs the actual work of reflowing the anonymous block child.
*/ void DoReflow();
/** * Schedules mPositions to be recomputed and the covered region to be * updated.
*/ void NotifyGlyphMetricsChange(bool aUpdateTextCorrespondence);
/** * Recomputes mPositions by calling DoGlyphPositioning if this information * is out of date.
*/ void UpdateGlyphPositioning();
/** * Populates mPositions with positioning information for each character * within the <text>.
*/ void DoGlyphPositioning();
/** * Converts the specified index into mPositions to an addressable * character index (as can be used with the SVG DOM text methods) * relative to the specified text child content element. * * @param aIndex The global character index. * @param aContent The descendant text child content element that * the returned addressable index will be relative to; null * means the same as the <text> element. * @return The addressable index, or -1 if the index cannot be * represented as an addressable index relative to aContent.
*/
int32_t ConvertTextElementCharIndexToAddressableIndex(int32_t aIndex,
nsIContent* aContent);
/** * Recursive helper for ResolvePositions below. * * @param aContent The current node. * @param aIndex (in/out) The current character index. * @param aInTextPath Whether we are currently under a <textPath> element. * @param aForceStartOfChunk (in/out) Whether the next character we find * should start a new anchored chunk. * @param aDeltas (in/out) Receives the resolved dx/dy values for each * character. * @return false if we discover that mPositions did not have enough * elements; true otherwise.
*/ bool ResolvePositionsForNode(nsIContent* aContent, uint32_t& aIndex, bool aInTextPath, bool& aForceStartOfChunk,
nsTArray<gfxPoint>& aDeltas);
/** * Initializes mPositions with character position information based on * x/y/rotate attributes, leaving unspecified values in the array if a * position was not given for that character. Also fills aDeltas with values * based on dx/dy attributes. * * @param aDeltas (in/out) Receives the resolved dx/dy values for each * character. * @param aRunPerGlyph Whether mPositions should record that a new run begins * at each glyph. * @return false if we did not record any positions (due to having no * displayed characters) or if we discover that mPositions did not have * enough elements; true otherwise.
*/ bool ResolvePositions(nsTArray<gfxPoint>& aDeltas, bool aRunPerGlyph);
/** * Determines the position, in app units, of each character in the <text> as * laid out by reflow, and appends them to aPositions. Any characters that * are undisplayed or trimmed away just get the last position.
*/ void DetermineCharPositions(nsTArray<nsPoint>& aPositions);
/** * Sets mStartOfChunk to true for each character in mPositions that starts a * line of text.
*/ void AdjustChunksForLineBreaks();
/** * Adjusts recorded character positions in mPositions to account for glyph * boundaries. Four things are done: * * 1. mClusterOrLigatureGroupMiddle is set to true for all such characters. * * 2. Any run and anchored chunk boundaries that begin in the middle of a * cluster/ligature group get moved to the start of the next * cluster/ligature group. * * 3. The position of any character in the middle of a cluster/ligature * group is updated to take into account partial ligatures and any * rotation the glyph as a whole has. (The values that come out of * DetermineCharPositions which then get written into mPositions in * ResolvePositions store the same position value for each part of the * ligature.) * * 4. The rotation of any character in the middle of a cluster/ligature * group is set to the rotation of the first character.
*/ void AdjustPositionsForClusters();
/** * Updates the character positions stored in mPositions to account for * text anchoring.
*/ void DoAnchoring();
/** * Updates character positions in mPositions for those characters inside a * <textPath>.
*/ void DoTextPathLayout();
/** * Returns whether we need to render the text using * nsTextFrame::DrawPathCallbacks rather than directly painting * the text frames. * * @param aShouldPaintSVGGlyphs (out) Whether SVG glyphs in the text * should be painted.
*/ bool ShouldRenderAsPath(nsTextFrame* aFrame, bool& aShouldPaintSVGGlyphs);
// Methods to get information for a <textPath> frame.
already_AddRefed<Path> GetTextPath(nsIFrame* aTextPathFrame);
gfxFloat GetOffsetScale(nsIFrame* aTextPathFrame);
gfxFloat GetStartOffset(nsIFrame* aTextPathFrame);
/** * The MutationObserver we have registered for the <text> element subtree.
*/
RefPtr<MutationObserver> mMutationObserver;
/** * The number of characters in the DOM after the final nsTextFrame. For * example, with * * <text>abcd<tspan display="none">ef</tspan></text> * * mTrailingUndisplayedCharacters would be 2.
*/
uint32_t mTrailingUndisplayedCharacters = 0;
/** * Computed position information for each DOM character within the <text>.
*/
nsTArray<CharPosition> mPositions;
/** * mFontSizeScaleFactor is used to cause the nsTextFrames to create text * runs with a font size different from the actual font-size property value. * This is used so that, for example with: * * <svg> * <g transform="scale(2)"> * <text font-size="10">abc</text> * </g> * </svg> * * a font size of 20 would be used. It's preferable to use a font size that * is identical or close to the size that the text will appear on the screen, * because at very small or large font sizes, text metrics will be computed * differently due to the limited precision that text runs have. * * mFontSizeScaleFactor is the amount the actual font-size property value * should be multiplied by to cause the text run font size to (a) be within a * "reasonable" range, and (b) be close to the actual size to be painted on * screen. (The "reasonable" range as determined by some #defines in * SVGTextFrame.cpp is 8..200.)
*/ float mFontSizeScaleFactor = 1.0f;
/** * The scale of the context that we last used to compute mFontSizeScaleFactor. * We record this so that we can tell when our scale transform has changed * enough to warrant reflowing the text.
*/ float mLastContextScale = 1.0f;
/** * The amount that we need to scale each rendered run to account for * lengthAdjust="spacingAndGlyphs".
*/ float mLengthAdjustScaleFactor = 1.0f;
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.