2017-10-27 20:33:53 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2013-02-11 10:22:16 +04:00
|
|
|
/* 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/. */
|
|
|
|
|
2013-12-20 20:38:51 +04:00
|
|
|
#ifndef MOZILLA_SVGTEXTFRAME_H
|
|
|
|
#define MOZILLA_SVGTEXTFRAME_H
|
2013-02-11 10:22:16 +04:00
|
|
|
|
2013-05-29 23:37:49 +04:00
|
|
|
#include "mozilla/Attributes.h"
|
2019-04-25 08:04:15 +03:00
|
|
|
#include "mozilla/PresShellForwards.h"
|
2015-10-18 08:24:48 +03:00
|
|
|
#include "mozilla/RefPtr.h"
|
2013-11-18 05:29:06 +04:00
|
|
|
#include "mozilla/gfx/2D.h"
|
2013-02-11 10:22:16 +04:00
|
|
|
#include "gfxMatrix.h"
|
|
|
|
#include "gfxRect.h"
|
2016-03-08 10:56:18 +03:00
|
|
|
#include "gfxTextRun.h"
|
2016-06-07 23:10:18 +03:00
|
|
|
#include "nsAutoPtr.h"
|
2014-08-18 18:44:50 +04:00
|
|
|
#include "nsIContent.h" // for GetContent
|
2013-02-11 10:22:16 +04:00
|
|
|
#include "nsStubMutationObserver.h"
|
2016-07-25 15:27:00 +03:00
|
|
|
#include "nsSVGContainerFrame.h"
|
2013-02-11 10:22:16 +04:00
|
|
|
|
2014-10-31 23:08:54 +03:00
|
|
|
class gfxContext;
|
2013-02-11 10:22:16 +04:00
|
|
|
class nsDisplaySVGText;
|
2013-12-20 20:38:51 +04:00
|
|
|
class SVGTextFrame;
|
2013-02-11 10:22:16 +04:00
|
|
|
class nsTextFrame;
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
2013-07-07 11:27:51 +04:00
|
|
|
class CharIterator;
|
2013-11-18 18:29:51 +04:00
|
|
|
class nsISVGPoint;
|
2013-02-11 10:22:16 +04:00
|
|
|
class TextFrameIterator;
|
|
|
|
class TextNodeCorrespondenceRecorder;
|
|
|
|
struct TextRenderedRun;
|
|
|
|
class TextRenderedRunIterator;
|
|
|
|
|
2013-03-26 19:53:13 +04:00
|
|
|
namespace dom {
|
2019-06-16 12:12:40 +03:00
|
|
|
struct DOMPointInit;
|
2019-06-20 17:03:54 +03:00
|
|
|
class SVGRect;
|
2018-03-13 22:52:03 +03:00
|
|
|
class SVGGeometryElement;
|
2015-07-13 18:25:42 +03:00
|
|
|
} // namespace dom
|
2013-03-26 19:53:13 +04:00
|
|
|
|
2013-02-11 10:22:16 +04:00
|
|
|
/**
|
|
|
|
* 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),
|
2013-04-16 12:28:21 +04:00
|
|
|
mStartOfChunk(false) {}
|
2013-02-11 10:22:16 +04:00
|
|
|
|
|
|
|
CharPosition(gfxPoint aPosition, double aAngle)
|
|
|
|
: mPosition(aPosition),
|
|
|
|
mAngle(aAngle),
|
|
|
|
mHidden(false),
|
|
|
|
mUnaddressable(false),
|
|
|
|
mClusterOrLigatureGroupMiddle(false),
|
|
|
|
mRunBoundary(false),
|
2013-04-16 12:28:21 +04:00
|
|
|
mStartOfChunk(false) {}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2013-02-11 10:22:16 +04:00
|
|
|
static CharPosition Unspecified(bool aUnaddressable) {
|
|
|
|
CharPosition cp(UnspecifiedPoint(), UnspecifiedAngle());
|
|
|
|
cp.mUnaddressable = aUnaddressable;
|
|
|
|
return cp;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsAngleSpecified() const { return mAngle != UnspecifiedAngle(); }
|
|
|
|
|
|
|
|
bool IsXSpecified() const { return mPosition.x != UnspecifiedCoord(); }
|
|
|
|
|
|
|
|
bool IsYSpecified() const { return mPosition.y != UnspecifiedCoord(); }
|
|
|
|
|
|
|
|
gfxPoint mPosition;
|
|
|
|
double mAngle;
|
|
|
|
|
|
|
|
// not displayed due to falling off the end of a <textPath>
|
|
|
|
bool mHidden;
|
|
|
|
|
|
|
|
// skipped in positioning attributes due to being collapsed-away white space
|
|
|
|
bool mUnaddressable;
|
|
|
|
|
|
|
|
// a preceding character is what positioning attributes address
|
|
|
|
bool mClusterOrLigatureGroupMiddle;
|
|
|
|
|
|
|
|
// rendering is split here since an explicit position or rotation was given
|
|
|
|
bool mRunBoundary;
|
|
|
|
|
|
|
|
// an anchored chunk begins here
|
|
|
|
bool mStartOfChunk;
|
|
|
|
|
|
|
|
private:
|
|
|
|
static gfxFloat UnspecifiedCoord() {
|
|
|
|
return std::numeric_limits<gfxFloat>::infinity();
|
|
|
|
}
|
|
|
|
|
|
|
|
static double UnspecifiedAngle() {
|
|
|
|
return std::numeric_limits<double>::infinity();
|
|
|
|
}
|
|
|
|
|
|
|
|
static gfxPoint UnspecifiedPoint() {
|
|
|
|
return gfxPoint(UnspecifiedCoord(), UnspecifiedCoord());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-02-15 08:29:28 +04:00
|
|
|
/**
|
|
|
|
* A runnable to mark glyph positions as needing to be recomputed
|
2013-12-20 20:38:51 +04:00
|
|
|
* and to invalid the bounds of the SVGTextFrame frame.
|
2013-02-15 08:29:28 +04:00
|
|
|
*/
|
2016-04-26 03:23:21 +03:00
|
|
|
class GlyphMetricsUpdater : public Runnable {
|
2013-02-15 08:29:28 +04:00
|
|
|
public:
|
|
|
|
NS_DECL_NSIRUNNABLE
|
2017-06-12 22:34:10 +03:00
|
|
|
explicit GlyphMetricsUpdater(SVGTextFrame* aFrame)
|
|
|
|
: Runnable("GlyphMetricsUpdater"), mFrame(aFrame) {}
|
2013-12-20 20:38:51 +04:00
|
|
|
static void Run(SVGTextFrame* aFrame);
|
2013-02-15 08:29:28 +04:00
|
|
|
void Revoke() { mFrame = nullptr; }
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2013-02-15 08:29:28 +04:00
|
|
|
private:
|
2013-12-20 20:38:51 +04:00
|
|
|
SVGTextFrame* mFrame;
|
2013-02-15 08:29:28 +04:00
|
|
|
};
|
|
|
|
|
2013-10-21 15:54:28 +04:00
|
|
|
} // namespace mozilla
|
2013-02-11 10:22:16 +04:00
|
|
|
|
|
|
|
/**
|
2016-01-11 02:48:56 +03:00
|
|
|
* Frame class for SVG <text> elements.
|
2013-02-11 10:22:16 +04:00
|
|
|
*
|
2013-12-20 20:38:51 +04:00
|
|
|
* An SVGTextFrame manages SVG text layout, painting and interaction for
|
2013-02-11 10:22:16 +04:00
|
|
|
* all descendent text content elements. The frame tree will look like this:
|
|
|
|
*
|
2013-12-20 20:38:51 +04:00
|
|
|
* SVGTextFrame -- for <text>
|
2013-02-11 10:22:16 +04:00
|
|
|
* <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.
|
|
|
|
*/
|
2016-04-18 10:54:36 +03:00
|
|
|
class SVGTextFrame final : public nsSVGDisplayContainerFrame {
|
2019-04-16 10:24:49 +03:00
|
|
|
friend nsIFrame* NS_NewSVGTextFrame(mozilla::PresShell* aPresShell,
|
2018-03-22 21:20:41 +03:00
|
|
|
ComputedStyle* aStyle);
|
2013-02-11 10:22:16 +04:00
|
|
|
|
2013-07-07 11:27:51 +04:00
|
|
|
friend class mozilla::CharIterator;
|
2013-02-15 08:29:28 +04:00
|
|
|
friend class mozilla::GlyphMetricsUpdater;
|
2013-02-11 10:22:16 +04:00
|
|
|
friend class mozilla::TextFrameIterator;
|
|
|
|
friend class mozilla::TextNodeCorrespondenceRecorder;
|
|
|
|
friend struct mozilla::TextRenderedRun;
|
|
|
|
friend class mozilla::TextRenderedRunIterator;
|
|
|
|
friend class MutationObserver;
|
|
|
|
friend class nsDisplaySVGText;
|
|
|
|
|
2016-03-08 10:56:18 +03:00
|
|
|
typedef gfxTextRun::Range Range;
|
2014-09-29 17:15:19 +04:00
|
|
|
typedef mozilla::gfx::DrawTarget DrawTarget;
|
2013-11-18 05:29:06 +04:00
|
|
|
typedef mozilla::gfx::Path Path;
|
2014-08-22 17:40:02 +04:00
|
|
|
typedef mozilla::gfx::Point Point;
|
2013-10-21 15:54:28 +04:00
|
|
|
|
2013-02-11 10:22:16 +04:00
|
|
|
protected:
|
2019-02-05 19:45:54 +03:00
|
|
|
explicit SVGTextFrame(ComputedStyle* aStyle, nsPresContext* aPresContext)
|
|
|
|
: nsSVGDisplayContainerFrame(aStyle, aPresContext, kClassID),
|
2016-12-01 11:06:50 +03:00
|
|
|
mTrailingUndisplayedCharacters(0),
|
2016-04-18 10:54:36 +03:00
|
|
|
mFontSizeScaleFactor(1.0f),
|
|
|
|
mLastContextScale(1.0f),
|
|
|
|
mLengthAdjustScaleFactor(1.0f) {
|
2017-09-01 20:07:40 +03:00
|
|
|
AddStateBits(NS_STATE_SVG_TEXT_CORRESPONDENCE_DIRTY |
|
|
|
|
NS_STATE_SVG_POSITIONING_DIRTY);
|
2013-02-11 10:22:16 +04:00
|
|
|
}
|
|
|
|
|
2019-04-18 01:38:02 +03:00
|
|
|
~SVGTextFrame() = default;
|
2014-06-24 02:40:01 +04:00
|
|
|
|
2013-02-11 10:22:16 +04:00
|
|
|
public:
|
|
|
|
NS_DECL_QUERYFRAME
|
2017-05-26 13:11:11 +03:00
|
|
|
NS_DECL_FRAMEARENA_HELPERS(SVGTextFrame)
|
2013-02-11 10:22:16 +04:00
|
|
|
|
|
|
|
// nsIFrame:
|
2014-05-25 02:20:40 +04:00
|
|
|
virtual void Init(nsIContent* aContent, nsContainerFrame* aParent,
|
2015-03-21 19:28:04 +03:00
|
|
|
nsIFrame* aPrevInFlow) override;
|
2013-02-11 10:22:16 +04:00
|
|
|
|
2014-02-18 11:47:48 +04:00
|
|
|
virtual nsresult AttributeChanged(int32_t aNamespaceID, nsAtom* aAttribute,
|
2015-03-21 19:28:04 +03:00
|
|
|
int32_t aModType) override;
|
2013-02-11 10:22:16 +04:00
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
virtual nsContainerFrame* GetContentInsertionFrame() override {
|
2016-01-29 17:42:14 +03:00
|
|
|
return PrincipalChildList().FirstChild()->GetContentInsertionFrame();
|
2013-02-11 10:22:16 +04:00
|
|
|
}
|
|
|
|
|
2013-02-14 15:12:27 +04:00
|
|
|
virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
2015-03-21 19:28:04 +03:00
|
|
|
const nsDisplayListSet& aLists) override;
|
2013-02-11 10:22:16 +04:00
|
|
|
|
2014-01-06 03:31:14 +04:00
|
|
|
#ifdef DEBUG_FRAME_DUMP
|
2015-03-21 19:28:04 +03:00
|
|
|
virtual nsresult GetFrameName(nsAString& aResult) const override {
|
2013-12-20 20:38:51 +04:00
|
|
|
return MakeFrameName(NS_LITERAL_STRING("SVGText"), aResult);
|
2013-02-11 10:22:16 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-03-22 21:20:41 +03:00
|
|
|
virtual void DidSetComputedStyle(ComputedStyle* aOldComputedStyle) override;
|
2013-06-03 18:15:29 +04:00
|
|
|
|
2013-02-11 10:22:18 +04:00
|
|
|
/**
|
|
|
|
* Finds the nsTextFrame for the closest rendered run to the specified point.
|
|
|
|
*/
|
2017-11-15 12:55:36 +03:00
|
|
|
virtual void FindCloserFrameForSelection(
|
|
|
|
const nsPoint& aPoint, FrameWithDistance* aCurrentBestFrame) override;
|
2013-06-03 18:15:29 +04:00
|
|
|
|
2017-02-09 21:24:31 +03:00
|
|
|
// nsSVGDisplayableFrame interface:
|
2015-03-21 19:28:04 +03:00
|
|
|
virtual void NotifySVGChanged(uint32_t aFlags) override;
|
2017-05-18 23:03:41 +03:00
|
|
|
virtual void PaintSVG(gfxContext& aContext, const gfxMatrix& aTransform,
|
|
|
|
imgDrawingParams& aImgParams,
|
|
|
|
const nsIntRect* aDirtyRect = nullptr) override;
|
2015-03-21 19:28:04 +03:00
|
|
|
virtual nsIFrame* GetFrameForPoint(const gfxPoint& aPoint) override;
|
|
|
|
virtual void ReflowSVG() override;
|
2013-12-30 10:50:07 +04:00
|
|
|
virtual SVGBBox GetBBoxContribution(const Matrix& aToBBoxUserspace,
|
2015-03-21 19:28:04 +03:00
|
|
|
uint32_t aFlags) override;
|
2013-02-11 10:22:16 +04:00
|
|
|
|
|
|
|
// SVG DOM text methods:
|
|
|
|
uint32_t GetNumberOfChars(nsIContent* aContent);
|
|
|
|
float GetComputedTextLength(nsIContent* aContent);
|
2013-04-01 13:43:38 +04:00
|
|
|
nsresult SelectSubString(nsIContent* aContent, uint32_t charnum,
|
|
|
|
uint32_t nchars);
|
2013-03-28 07:31:31 +04:00
|
|
|
nsresult GetSubStringLength(nsIContent* aContent, uint32_t charnum,
|
|
|
|
uint32_t nchars, float* aResult);
|
2013-02-11 10:22:16 +04:00
|
|
|
int32_t GetCharNumAtPosition(nsIContent* aContent,
|
2019-06-16 12:12:40 +03:00
|
|
|
const mozilla::dom::DOMPointInit& aPoint);
|
2013-02-11 10:22:16 +04:00
|
|
|
|
|
|
|
nsresult GetStartPositionOfChar(nsIContent* aContent, uint32_t aCharNum,
|
|
|
|
mozilla::nsISVGPoint** aResult);
|
|
|
|
nsresult GetEndPositionOfChar(nsIContent* aContent, uint32_t aCharNum,
|
|
|
|
mozilla::nsISVGPoint** aResult);
|
|
|
|
nsresult GetExtentOfChar(nsIContent* aContent, uint32_t aCharNum,
|
2019-06-20 17:03:54 +03:00
|
|
|
mozilla::dom::SVGRect** aResult);
|
2013-02-11 10:22:16 +04:00
|
|
|
nsresult GetRotationOfChar(nsIContent* aContent, uint32_t aCharNum,
|
|
|
|
float* aResult);
|
|
|
|
|
2013-12-20 20:38:51 +04:00
|
|
|
// SVGTextFrame methods:
|
2013-02-11 10:22:16 +04:00
|
|
|
|
2014-09-08 06:34:20 +04:00
|
|
|
/**
|
|
|
|
* Handles a base or animated attribute value change to a descendant
|
|
|
|
* text content element.
|
|
|
|
*/
|
|
|
|
void HandleAttributeChangeInDescendant(mozilla::dom::Element* aElement,
|
|
|
|
int32_t aNameSpaceID,
|
2017-10-03 01:05:19 +03:00
|
|
|
nsAtom* aAttribute);
|
2014-09-08 06:34:20 +04:00
|
|
|
|
2013-02-11 10:22:16 +04:00
|
|
|
/**
|
|
|
|
* Schedules mPositions to be recomputed and the covered region to be
|
2013-06-12 07:19:52 +04:00
|
|
|
* updated.
|
2013-03-28 03:55:55 +04:00
|
|
|
*/
|
2013-06-12 07:19:52 +04:00
|
|
|
void NotifyGlyphMetricsChange();
|
2013-02-11 10:22:16 +04:00
|
|
|
|
2013-06-22 06:38:57 +04:00
|
|
|
/**
|
|
|
|
* Calls ScheduleReflowSVGNonDisplayText if this is a non-display frame,
|
|
|
|
* and nsSVGUtils::ScheduleReflowSVG otherwise.
|
|
|
|
*/
|
|
|
|
void ScheduleReflowSVG();
|
|
|
|
|
2013-06-03 18:15:29 +04:00
|
|
|
/**
|
2013-12-20 20:38:51 +04:00
|
|
|
* Reflows the anonymous block frame of this non-display SVGTextFrame.
|
2013-06-03 18:15:29 +04:00
|
|
|
*
|
|
|
|
* When we are under nsSVGDisplayContainerFrame::ReflowSVG, we need to
|
2013-12-20 20:38:51 +04:00
|
|
|
* reflow any SVGTextFrame frames in the subtree in case they are
|
2013-06-03 18:15:29 +04:00
|
|
|
* being observed (by being for example in a <mask>) and the change
|
|
|
|
* that caused the reflow would not already have caused a reflow.
|
|
|
|
*
|
2013-12-20 20:38:51 +04:00
|
|
|
* Note that displayed SVGTextFrames are reflowed as needed, when PaintSVG
|
2013-06-03 18:15:29 +04:00
|
|
|
* is called or some SVG DOM method is called on the element.
|
2013-06-03 18:15:29 +04:00
|
|
|
*/
|
|
|
|
void ReflowSVGNonDisplayText();
|
|
|
|
|
2013-06-03 18:15:29 +04:00
|
|
|
/**
|
|
|
|
* This is a function that behaves similarly to nsSVGUtils::ScheduleReflowSVG,
|
|
|
|
* but which will skip over any ancestor non-display container frames on the
|
|
|
|
* way to the nsSVGOuterSVGFrame. 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
|
|
|
|
* nsSVGDisplayContainerFrame::ReflowSVG will call ReflowSVGNonDisplayText on
|
|
|
|
* it.
|
|
|
|
*
|
2016-08-01 03:08:56 +03:00
|
|
|
* We have to do this in two cases: in response to a style change on a
|
|
|
|
* non-display <text>, where aReason will be eStyleChange (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 eResize,
|
|
|
|
* since layout doesn't need to be recomputed.
|
2013-06-03 18:15:29 +04:00
|
|
|
*/
|
2019-04-25 08:04:15 +03:00
|
|
|
void ScheduleReflowSVGNonDisplayText(mozilla::IntrinsicDirty aReason);
|
2013-06-03 18:15:29 +04:00
|
|
|
|
2013-02-11 10:22:16 +04:00
|
|
|
/**
|
|
|
|
* Updates the mFontSizeScaleFactor value by looking at the range of
|
|
|
|
* font-sizes used within the <text>.
|
2013-07-07 11:27:51 +04:00
|
|
|
*
|
|
|
|
* @return Whether mFontSizeScaleFactor changed.
|
2013-02-11 10:22:16 +04:00
|
|
|
*/
|
2013-07-07 11:27:51 +04:00
|
|
|
bool UpdateFontSizeScaleFactor();
|
2013-02-11 10:22:16 +04:00
|
|
|
|
|
|
|
double GetFontSizeScaleFactor() const;
|
|
|
|
|
2013-02-11 10:22:18 +04:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2014-08-22 17:40:02 +04:00
|
|
|
Point TransformFramePointToTextChild(const Point& aPoint,
|
|
|
|
nsIFrame* aChildFrame);
|
2013-02-11 10:22:18 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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,
|
2018-05-29 02:58:25 +03:00
|
|
|
const nsIFrame* aChildFrame);
|
2013-02-11 10:22:18 +04:00
|
|
|
|
2017-06-16 12:22:33 +03:00
|
|
|
// Return our ::-moz-svg-text anonymous box.
|
|
|
|
void AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult) override;
|
2017-03-15 21:00:43 +03:00
|
|
|
|
2013-02-11 10:22:16 +04:00
|
|
|
private:
|
|
|
|
/**
|
|
|
|
* Mutation observer used to watch for text positioning attribute changes
|
|
|
|
* on descendent text content elements (like <tspan>s).
|
|
|
|
*/
|
2015-03-21 19:28:04 +03:00
|
|
|
class MutationObserver final : public nsStubMutationObserver {
|
2013-02-11 10:22:16 +04:00
|
|
|
public:
|
2014-09-01 07:36:37 +04:00
|
|
|
explicit MutationObserver(SVGTextFrame* aFrame) : mFrame(aFrame) {
|
2014-07-02 14:09:00 +04:00
|
|
|
MOZ_ASSERT(mFrame, "MutationObserver needs a non-null frame");
|
|
|
|
mFrame->GetContent()->AddMutationObserver(this);
|
2013-02-11 10:22:16 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// nsISupports
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
|
|
|
|
// nsIMutationObserver
|
|
|
|
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
|
|
|
|
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
|
|
|
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
|
2013-06-22 06:38:57 +04:00
|
|
|
NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
|
2013-02-11 10:22:17 +04:00
|
|
|
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
|
2013-02-11 10:22:16 +04:00
|
|
|
|
|
|
|
private:
|
2014-07-02 14:09:00 +04:00
|
|
|
~MutationObserver() { mFrame->GetContent()->RemoveMutationObserver(this); }
|
|
|
|
|
|
|
|
SVGTextFrame* const mFrame;
|
2013-02-11 10:22:16 +04:00
|
|
|
};
|
|
|
|
|
2017-08-16 14:48:21 +03:00
|
|
|
/**
|
|
|
|
* Resolves Bidi for the anonymous block child if it needs it.
|
|
|
|
*/
|
|
|
|
void MaybeResolveBidiForAnonymousBlockChild();
|
|
|
|
|
2013-02-11 10:22:16 +04:00
|
|
|
/**
|
2013-06-03 18:15:29 +04:00
|
|
|
* Reflows the anonymous block child if it is dirty or has dirty
|
2013-12-20 20:38:51 +04:00
|
|
|
* children, or if the SVGTextFrame itself is dirty.
|
2013-02-11 10:22:16 +04:00
|
|
|
*/
|
2013-06-03 18:15:29 +04:00
|
|
|
void MaybeReflowAnonymousBlockChild();
|
2013-02-11 10:22:16 +04:00
|
|
|
|
|
|
|
/**
|
2013-06-03 18:15:29 +04:00
|
|
|
* Performs the actual work of reflowing the anonymous block child.
|
2013-02-11 10:22:16 +04:00
|
|
|
*/
|
2013-06-03 18:15:29 +04:00
|
|
|
void DoReflow();
|
2013-02-11 10:22:16 +04:00
|
|
|
|
|
|
|
/**
|
2013-06-03 18:15:29 +04:00
|
|
|
* Recomputes mPositions by calling DoGlyphPositioning if this information
|
|
|
|
* is out of date.
|
2013-02-11 10:22:16 +04:00
|
|
|
*/
|
2013-05-30 11:53:07 +04:00
|
|
|
void UpdateGlyphPositioning();
|
2013-02-11 10:22:16 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Populates mPositions with positioning information for each character
|
|
|
|
* within the <text>.
|
|
|
|
*/
|
|
|
|
void DoGlyphPositioning();
|
|
|
|
|
2017-09-03 00:22:54 +03:00
|
|
|
/**
|
|
|
|
* This fallback version of GetSubStringLength that flushes layout and takes
|
|
|
|
* into account glyph positioning. 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.
|
|
|
|
*/
|
2019-04-13 15:43:57 +03:00
|
|
|
MOZ_CAN_RUN_SCRIPT_BOUNDARY
|
2017-09-03 00:22:54 +03:00
|
|
|
nsresult GetSubStringLengthSlowFallback(nsIContent* aContent,
|
|
|
|
uint32_t charnum, uint32_t nchars,
|
|
|
|
float* aResult);
|
|
|
|
|
2013-02-19 06:50:05 +04:00
|
|
|
/**
|
|
|
|
* 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);
|
|
|
|
|
2013-02-11 10:22:16 +04:00
|
|
|
/**
|
|
|
|
* Recursive helper for ResolvePositions below.
|
|
|
|
*
|
|
|
|
* @param aContent The current node.
|
2015-04-06 16:11:55 +03:00
|
|
|
* @param aIndex (in/out) The current character index.
|
2013-02-11 10:22:16 +04:00
|
|
|
* @param aInTextPath Whether we are currently under a <textPath> element.
|
2015-04-06 16:11:55 +03:00
|
|
|
* @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.
|
2013-02-11 10:22:16 +04:00
|
|
|
*/
|
2015-04-06 16:11:55 +03:00
|
|
|
bool ResolvePositionsForNode(nsIContent* aContent, uint32_t& aIndex,
|
|
|
|
bool aInTextPath, bool& aForceStartOfChunk,
|
|
|
|
nsTArray<gfxPoint>& aDeltas);
|
2013-02-11 10:22:16 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*
|
2015-04-06 16:11:55 +03:00
|
|
|
* @param aDeltas (in/out) Receives the resolved dx/dy values for each
|
|
|
|
* character.
|
2013-07-07 11:27:51 +04:00
|
|
|
* @param aRunPerGlyph Whether mPositions should record that a new run begins
|
|
|
|
* at each glyph.
|
2015-04-06 16:11:55 +03:00
|
|
|
* @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.
|
2013-02-11 10:22:16 +04:00
|
|
|
*/
|
2013-07-07 11:27:51 +04:00
|
|
|
bool ResolvePositions(nsTArray<gfxPoint>& aDeltas, bool aRunPerGlyph);
|
2013-02-11 10:22:16 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
2013-02-11 10:22:20 +04:00
|
|
|
*
|
|
|
|
* @param aShouldPaintSVGGlyphs (out) Whether SVG glyphs in the text
|
|
|
|
* should be painted.
|
2013-02-11 10:22:16 +04:00
|
|
|
*/
|
2014-10-31 23:08:54 +03:00
|
|
|
bool ShouldRenderAsPath(nsTextFrame* aFrame, bool& aShouldPaintSVGGlyphs);
|
2013-02-11 10:22:16 +04:00
|
|
|
|
|
|
|
// Methods to get information for a <textPath> frame.
|
2015-06-17 17:00:52 +03:00
|
|
|
already_AddRefed<Path> GetTextPath(nsIFrame* aTextPathFrame);
|
2013-02-11 10:22:16 +04:00
|
|
|
gfxFloat GetOffsetScale(nsIFrame* aTextPathFrame);
|
|
|
|
gfxFloat GetStartOffset(nsIFrame* aTextPathFrame);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The MutationObserver we have registered for the <text> element subtree.
|
|
|
|
*/
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<MutationObserver> mMutationObserver;
|
2013-02-11 10:22:16 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Computed position information for each DOM character within the <text>.
|
|
|
|
*/
|
|
|
|
nsTArray<mozilla::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>
|
2013-04-20 15:24:34 +04:00
|
|
|
* </svg>
|
2013-02-11 10:22:16 +04:00
|
|
|
*
|
|
|
|
* 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
|
2013-12-20 20:38:51 +04:00
|
|
|
* SVGTextFrame.cpp is 8..200.)
|
2013-02-11 10:22:16 +04:00
|
|
|
*/
|
|
|
|
float mFontSizeScaleFactor;
|
|
|
|
|
2013-07-07 11:27:51 +04:00
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The amount that we need to scale each rendered run to account for
|
|
|
|
* lengthAdjust="spacingAndGlyphs".
|
|
|
|
*/
|
|
|
|
float mLengthAdjustScaleFactor;
|
2013-02-11 10:22:16 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|