import changes from `dev' branch of rmottola/Arctic-Fox:

- Bug 1158090 - Fix documentation for nsDisplayListBuilder constructor. r=roc (773b76e1b3)
- Bug 1153510 - Improve handling of vertical writing mode in SVG text frames. r=longsonr (bd513aa02e)
- Bug 1156366 - Support vertical writing modes and upright/sideways gly# ph orientation in SVG text-on-a-path. r=longsonr (325c3c2e00)
- Bug 1157951 patch 1 - Rename fields and variables in nsCharClipDisplayItem etc using VisIStart/End instead of left/right. r=roc (bc4aa0e75a)
- Fix nsDisplayCanvasBackgroundColor to invalidate on color changes. (bug 1205970 part 1, r=mattwoodrow) (e51b8489a6)
- Bug 1151663 - Initialize display list builder flags earlier in nsLayoutUtils::PaintFrame(). r=tn (fb55eaf2d8)
- Remove willFlushRetainedLayers, which is superceded by DLBI. (bug 1205970 part 2, r=mattwoodrow) (0651277211)
- Bug 1166301 - Layerize background images fixed to child elements. r=mattwoodrow (fb979f8c89)
- Bug 1166301 - If APZ is enabled, only clip fixed background images to the viewport area. r=mattwoodrow (96944fa488)
- Bug 885515 - Part 1: Add an analysis for detecting non-heap allocations of MOZ_HEAP_CLASS, r=ehsan (b1c53befae)
- Bug 1192271 - Add helper method CustomTypeAnnotation::reportErrorIfAbsent to clang-plugin, r=ehsan (627b9d0c4c)
- Bug 1195960 - Correct naming of CustomTypeAnnotation::reportErrorIfAbsent, r=me (cdba688d80)
This commit is contained in:
2022-02-06 22:41:15 +08:00
parent a988f766e4
commit 5c42a5c6d1
14 changed files with 442 additions and 324 deletions
+20 -30
View File
@@ -256,6 +256,15 @@ public:
}
void dumpAnnotationReason(DiagnosticsEngine &Diag, QualType T, SourceLocation Loc);
void reportErrorIfPresent(DiagnosticsEngine &Diag, QualType T, SourceLocation Loc,
unsigned ErrorID, unsigned NoteID) {
if (hasEffectiveAnnotation(T)) {
Diag.Report(Loc, ErrorID) << T;
Diag.Report(Loc, NoteID);
dumpAnnotationReason(Diag, T, Loc);
}
}
private:
bool hasLiteralAnnotation(QualType T) const;
AnnotationReason directAnnotationReason(QualType T);
@@ -267,6 +276,8 @@ static CustomTypeAnnotation GlobalClass =
CustomTypeAnnotation("moz_global_class", "global");
static CustomTypeAnnotation NonHeapClass =
CustomTypeAnnotation("moz_nonheap_class", "non-heap");
static CustomTypeAnnotation HeapClass =
CustomTypeAnnotation("moz_heap_class", "heap");
static CustomTypeAnnotation MustUse =
CustomTypeAnnotation("moz_must_use", "must-use");
@@ -1111,45 +1122,24 @@ void DiagnosticsMatcher::ScopeChecker::run(
return;
case AV_Global:
if (StackClass.hasEffectiveAnnotation(T)) {
Diag.Report(Loc, StackID) << T;
Diag.Report(Loc, GlobalNoteID);
StackClass.dumpAnnotationReason(Diag, T, Loc);
}
StackClass.reportErrorIfPresent(Diag, T, Loc, StackID, GlobalNoteID);
HeapClass.reportErrorIfPresent(Diag, T, Loc, HeapID, GlobalNoteID);
break;
case AV_Automatic:
if (GlobalClass.hasEffectiveAnnotation(T)) {
Diag.Report(Loc, GlobalID) << T;
Diag.Report(Loc, StackNoteID);
GlobalClass.dumpAnnotationReason(Diag, T, Loc);
}
GlobalClass.reportErrorIfPresent(Diag, T, Loc, GlobalID, StackNoteID);
HeapClass.reportErrorIfPresent(Diag, T, Loc, HeapID, StackNoteID);
break;
case AV_Temporary:
if (GlobalClass.hasEffectiveAnnotation(T)) {
Diag.Report(Loc, GlobalID) << T;
Diag.Report(Loc, TemporaryNoteID);
GlobalClass.dumpAnnotationReason(Diag, T, Loc);
}
GlobalClass.reportErrorIfPresent(Diag, T, Loc, GlobalID, TemporaryNoteID);
HeapClass.reportErrorIfPresent(Diag, T, Loc, HeapID, TemporaryNoteID);
break;
case AV_Heap:
if (GlobalClass.hasEffectiveAnnotation(T)) {
Diag.Report(Loc, GlobalID) << T;
Diag.Report(Loc, HeapNoteID);
GlobalClass.dumpAnnotationReason(Diag, T, Loc);
}
if (StackClass.hasEffectiveAnnotation(T)) {
Diag.Report(Loc, StackID) << T;
Diag.Report(Loc, HeapNoteID);
StackClass.dumpAnnotationReason(Diag, T, Loc);
}
if (NonHeapClass.hasEffectiveAnnotation(T)) {
Diag.Report(Loc, NonHeapID) << T;
Diag.Report(Loc, HeapNoteID);
NonHeapClass.dumpAnnotationReason(Diag, T, Loc);
}
GlobalClass.reportErrorIfPresent(Diag, T, Loc, GlobalID, HeapNoteID);
StackClass.reportErrorIfPresent(Diag, T, Loc, StackID, HeapNoteID);
NonHeapClass.reportErrorIfPresent(Diag, T, Loc, NonHeapID, HeapNoteID);
break;
}
}
@@ -0,0 +1,64 @@
#define MOZ_HEAP_CLASS __attribute__((annotate("moz_heap_class")))
#define MOZ_IMPLICIT __attribute__((annotate("moz_implicit")))
#include <stddef.h>
struct MOZ_HEAP_CLASS Heap {
int i;
Heap() {}
MOZ_IMPLICIT Heap(int i) {}
Heap(int i, int j) {}
void *operator new(size_t x) throw() { return 0; }
void *operator new(size_t blah, char *buffer) { return buffer; }
};
template <class T>
struct MOZ_HEAP_CLASS TemplateClass {
T i;
};
void gobble(void *) { }
void gobbleref(const Heap&) { }
void misuseHeapClass(int len) {
Heap invalid; // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in an automatic variable}}
Heap alsoInvalid[2]; // expected-error {{variable of type 'Heap [2]' only valid on the heap}} expected-note {{value incorrectly allocated in an automatic variable}} expected-note {{'Heap [2]' is a heap type because it is an array of heap type 'Heap'}}
static Heap invalidStatic; // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a global variable}}
static Heap alsoInvalidStatic[2]; // expected-error {{variable of type 'Heap [2]' only valid on the heap}} expected-note {{value incorrectly allocated in a global variable}} expected-note {{'Heap [2]' is a heap type because it is an array of heap type 'Heap'}}
gobble(&invalid);
gobble(&invalidStatic);
gobble(&alsoInvalid[0]);
gobbleref(Heap()); // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a temporary}}
gobbleref(Heap(10, 20)); // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a temporary}}
gobbleref(Heap(10)); // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a temporary}}
gobbleref(10); // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a temporary}}
gobble(new Heap);
gobble(new Heap[10]);
gobble(new TemplateClass<int>);
gobble(len <= 5 ? &invalid : new Heap);
char buffer[sizeof(Heap)];
gobble(new (buffer) Heap);
}
Heap invalidStatic; // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a global variable}}
struct RandomClass {
Heap nonstaticMember; // expected-note {{'RandomClass' is a heap type because member 'nonstaticMember' is a heap type 'Heap'}}
static Heap staticMember; // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a global variable}}
};
struct MOZ_HEAP_CLASS RandomHeapClass {
Heap nonstaticMember;
static Heap staticMember; // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a global variable}}
};
struct BadInherit : Heap {}; // expected-note {{'BadInherit' is a heap type because it inherits from a heap type 'Heap'}}
struct MOZ_HEAP_CLASS GoodInherit : Heap {};
void useStuffWrongly() {
BadInherit i; // expected-error {{variable of type 'BadInherit' only valid on the heap}} expected-note {{value incorrectly allocated in an automatic variable}}
RandomClass r; // expected-error {{variable of type 'RandomClass' only valid on the heap}} expected-note {{value incorrectly allocated in an automatic variable}}
}
+1
View File
@@ -12,6 +12,7 @@ SOURCES += [
'TestCustomHeap.cpp',
'TestExplicitOperatorBool.cpp',
'TestGlobalClass.cpp',
'TestHeapClass.cpp',
'TestInheritTypeAnnotationsFromTemplateArgs.cpp',
'TestMultipleAnnotations.cpp',
'TestMustOverride.cpp',
+23 -17
View File
@@ -1502,10 +1502,6 @@ already_AddRefed<LayerManager> nsDisplayList::PaintRoot(nsDisplayListBuilder* aB
layerBuilder->SetLayerTreeCompressionMode();
}
if (aFlags & PAINT_FLUSH_LAYERS) {
FrameLayerBuilder::InvalidateAllLayers(layerManager);
}
if (doBeginTransaction) {
if (aCtx) {
layerManager->BeginTransactionWithTarget(aCtx->ThebesContext());
@@ -1702,10 +1698,6 @@ already_AddRefed<LayerManager> nsDisplayList::PaintRoot(nsDisplayListBuilder* aB
}
}
if (aFlags & PAINT_FLUSH_LAYERS) {
FrameLayerBuilder::InvalidateAllLayers(layerManager);
}
layerManager->SetUserData(&gLayerManagerLayerBuilder, oldBuilder);
return layerManager.forget();
}
@@ -2348,20 +2340,25 @@ nsDisplayBackgroundImage::IsSingleFixedPositionImage(nsDisplayListBuilder* aBuil
return true;
}
bool
nsDisplayBackgroundImage::IsNonEmptyFixedImage() const
{
return mBackgroundStyle->mLayers[mLayer].mAttachment == NS_STYLE_BG_ATTACHMENT_FIXED &&
!mBackgroundStyle->mLayers[mLayer].mImage.IsEmpty();
}
bool
nsDisplayBackgroundImage::ShouldFixToViewport(LayerManager* aManager)
{
// APZ doesn't (yet) know how to scroll the visible region for these type of
// items, so don't layerize them if it's enabled.
if (nsLayoutUtils::UsesAsyncScrolling(mFrame) ||
(aManager && aManager->ShouldAvoidComponentAlphaLayers())) {
// APZ needs background-attachment:fixed images layerized for correctness.
if (!nsLayoutUtils::UsesAsyncScrolling(mFrame) &&
aManager && aManager->ShouldAvoidComponentAlphaLayers()) {
return false;
}
// Put background-attachment:fixed background images in their own
// compositing layer, unless we have APZ enabled
return mBackgroundStyle->mLayers[mLayer].mAttachment == NS_STYLE_BG_ATTACHMENT_FIXED &&
!mBackgroundStyle->mLayers[mLayer].mImage.IsEmpty();
// compositing layer.
return IsNonEmptyFixedImage();
}
bool
@@ -2787,6 +2784,15 @@ nsDisplayBackgroundImage::GetBoundsInternal(nsDisplayListBuilder* aBuilder) {
if (mFrame->GetType() == nsGkAtoms::canvasFrame) {
nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
clipRect = frame->CanvasArea() + ToReferenceFrame();
} else if (nsLayoutUtils::UsesAsyncScrolling(mFrame) && IsNonEmptyFixedImage()) {
// If this is a background-attachment:fixed image, and APZ is enabled,
// async scrolling could reveal additional areas of the image, so don't
// clip it beyond clipping to the document's viewport.
nsIFrame* rootFrame = presContext->PresShell()->GetRootFrame();
nsRect rootRect = rootFrame->GetRectRelativeToSelf();
if (nsLayoutUtils::TransformRect(rootFrame, mFrame, rootRect) == nsLayoutUtils::TRANSFORM_SUCCEEDED) {
clipRect = rootRect + aBuilder->ToReferenceFrame(mFrame);
}
}
const nsStyleBackground::Layer& layer = mBackgroundStyle->mLayers[mLayer];
return nsCSSRendering::GetBackgroundLayerRect(presContext, mFrame,
@@ -5796,8 +5802,8 @@ nsCharClipDisplayItem::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
bool snap;
nsRect newRect = geometry->mBounds;
nsRect oldRect = GetBounds(aBuilder, &snap);
if (mLeftEdge != geometry->mLeftEdge ||
mRightEdge != geometry->mRightEdge ||
if (mVisIStartEdge != geometry->mVisIStartEdge ||
mVisIEndEdge != geometry->mVisIEndEdge ||
!oldRect.IsEqualInterior(newRect) ||
!geometry->mBorderRect.IsEqualInterior(GetBorderRect())) {
aInvalidRegion->Or(oldRect, newRect);
+75 -60
View File
@@ -166,8 +166,7 @@ public:
/**
* @param aReferenceFrame the frame at the root of the subtree; its origin
* is the origin of the reference coordinate system for this display list
* @param aIsForEvents true if we're creating this list in order to
* determine which frame is under the mouse position
* @param aMode encodes what the builder is being used for.
* @param aBuildCaret whether or not we should include the caret in any
* display lists that we make.
*/
@@ -1983,9 +1982,6 @@ public:
* otherwise we will use a temporary BasicLayerManager and ctx must
* not be null.
*
* If PAINT_FLUSH_LAYERS is set, we'll force a completely new layer
* tree to be created for this paint *and* the next paint.
*
* If PAINT_EXISTING_TRANSACTION is set, the reference frame's widget's
* layer manager has already had BeginTransaction() called on it and
* we should not call it again.
@@ -2002,7 +1998,6 @@ public:
enum {
PAINT_DEFAULT = 0,
PAINT_USE_WIDGET_LAYERS = 0x01,
PAINT_FLUSH_LAYERS = 0x02,
PAINT_EXISTING_TRANSACTION = 0x04,
PAINT_NO_COMPOSITE = 0x08,
PAINT_COMPRESSED = 0x10
@@ -2412,40 +2407,11 @@ protected:
* is not yet a frame tree to go in the frame/iframe so we use the subdoc
* frame of the parent document as a standin.
*/
class nsDisplaySolidColor : public nsDisplayItem {
class nsDisplaySolidColorBase : public nsDisplayItem {
public:
nsDisplaySolidColor(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
const nsRect& aBounds, nscolor aColor)
: nsDisplayItem(aBuilder, aFrame), mBounds(aBounds), mColor(aColor)
{
NS_ASSERTION(NS_GET_A(aColor) > 0, "Don't create invisible nsDisplaySolidColors!");
MOZ_COUNT_CTOR(nsDisplaySolidColor);
}
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplaySolidColor() {
MOZ_COUNT_DTOR(nsDisplaySolidColor);
}
#endif
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override;
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap) override {
*aSnap = false;
nsRegion result;
if (NS_GET_A(mColor) == 255) {
result = GetBounds(aBuilder, aSnap);
}
return result;
}
virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) override
{
*aColor = mColor;
return true;
}
virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) override;
nsDisplaySolidColorBase(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nscolor aColor)
: nsDisplayItem(aBuilder, aFrame), mColor(aColor)
{}
virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override
{
@@ -2466,13 +2432,51 @@ public:
ComputeInvalidationRegionDifference(aBuilder, geometry, aInvalidRegion);
}
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap) override {
*aSnap = false;
nsRegion result;
if (NS_GET_A(mColor) == 255) {
result = GetBounds(aBuilder, aSnap);
}
return result;
}
virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) override
{
*aColor = mColor;
return true;
}
protected:
nscolor mColor;
};
class nsDisplaySolidColor : public nsDisplaySolidColorBase {
public:
nsDisplaySolidColor(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
const nsRect& aBounds, nscolor aColor)
: nsDisplaySolidColorBase(aBuilder, aFrame, aColor), mBounds(aBounds)
{
NS_ASSERTION(NS_GET_A(aColor) > 0, "Don't create invisible nsDisplaySolidColors!");
MOZ_COUNT_CTOR(nsDisplaySolidColor);
}
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplaySolidColor() {
MOZ_COUNT_DTOR(nsDisplaySolidColor);
}
#endif
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override;
virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) override;
virtual void WriteDebugInfo(std::stringstream& aStream) override;
NS_DISPLAY_DECL_NAME("SolidColor", TYPE_SOLID_COLOR)
private:
nsRect mBounds;
nscolor mColor;
};
/**
@@ -2566,6 +2570,7 @@ protected:
bool IsSingleFixedPositionImage(nsDisplayListBuilder* aBuilder,
const nsRect& aClipRect,
gfxRect* aDestRect);
bool IsNonEmptyFixedImage() const;
nsRect GetBoundsInternal(nsDisplayListBuilder* aBuilder);
void PaintInternal(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx,
@@ -3884,11 +3889,12 @@ private:
};
/**
* This class adds basic support for limiting the rendering to the part inside
* the specified edges. It's a base class for the display item classes that
* does the actual work. The two members, mLeftEdge and mRightEdge, are
* relative to the edges of the frame's scrollable overflow rectangle and is
* the amount to suppress on each side.
* This class adds basic support for limiting the rendering (in the inline axis
* of the writing mode) to the part inside the specified edges. It's a base
* class for the display item classes that do the actual work.
* The two members, mVisIStartEdge and mVisIEndEdge, are relative to the edges
* of the frame's scrollable overflow rectangle and are the amount to suppress
* on each side.
*
* Setting none, both or only one edge is allowed.
* The values must be non-negative.
@@ -3897,7 +3903,7 @@ private:
class nsCharClipDisplayItem : public nsDisplayItem {
public:
nsCharClipDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
: nsDisplayItem(aBuilder, aFrame), mLeftEdge(0), mRightEdge(0) {}
: nsDisplayItem(aBuilder, aFrame), mVisIStartEdge(0), mVisIEndEdge(0) {}
explicit nsCharClipDisplayItem(nsIFrame* aFrame)
: nsDisplayItem(aFrame) {}
@@ -3910,27 +3916,33 @@ public:
struct ClipEdges {
ClipEdges(const nsDisplayItem& aItem,
nscoord aLeftEdge, nscoord aRightEdge) {
nscoord aVisIStartEdge, nscoord aVisIEndEdge) {
nsRect r = aItem.Frame()->GetScrollableOverflowRect() +
aItem.ToReferenceFrame();
if (aItem.Frame()->GetWritingMode().IsVertical()) {
mX = aLeftEdge > 0 ? r.y + aLeftEdge : nscoord_MIN;
mXMost = aRightEdge > 0 ? std::max(r.YMost() - aRightEdge, mX) : nscoord_MAX;
mVisIStart = aVisIStartEdge > 0 ? r.y + aVisIStartEdge : nscoord_MIN;
mVisIEnd =
aVisIEndEdge > 0 ? std::max(r.YMost() - aVisIEndEdge, mVisIStart)
: nscoord_MAX;
} else {
mX = aLeftEdge > 0 ? r.x + aLeftEdge : nscoord_MIN;
mXMost = aRightEdge > 0 ? std::max(r.XMost() - aRightEdge, mX) : nscoord_MAX;
mVisIStart = aVisIStartEdge > 0 ? r.x + aVisIStartEdge : nscoord_MIN;
mVisIEnd =
aVisIEndEdge > 0 ? std::max(r.XMost() - aVisIEndEdge, mVisIStart)
: nscoord_MAX;
}
}
void Intersect(nscoord* aX, nscoord* aWidth) const {
nscoord xmost1 = *aX + *aWidth;
*aX = std::max(*aX, mX);
*aWidth = std::max(std::min(xmost1, mXMost) - *aX, 0);
void Intersect(nscoord* aVisIStart, nscoord* aVisISize) const {
nscoord end = *aVisIStart + *aVisISize;
*aVisIStart = std::max(*aVisIStart, mVisIStart);
*aVisISize = std::max(std::min(end, mVisIEnd) - *aVisIStart, 0);
}
nscoord mX;
nscoord mXMost;
nscoord mVisIStart;
nscoord mVisIEnd;
};
ClipEdges Edges() const { return ClipEdges(*this, mLeftEdge, mRightEdge); }
ClipEdges Edges() const {
return ClipEdges(*this, mVisIStartEdge, mVisIEndEdge);
}
static nsCharClipDisplayItem* CheckCast(nsDisplayItem* aItem) {
nsDisplayItem::Type t = aItem->GetType();
@@ -3940,8 +3952,11 @@ public:
? static_cast<nsCharClipDisplayItem*>(aItem) : nullptr;
}
nscoord mLeftEdge; // length from the left side
nscoord mRightEdge; // length from the right side
// Lengths measured from the visual inline start and end sides
// (i.e. left and right respectively in horizontal writing modes,
// regardless of bidi directionality; top and bottom in vertical modes).
nscoord mVisIStartEdge;
nscoord mVisIEndEdge;
};
/**
+2 -2
View File
@@ -119,8 +119,8 @@ nsDisplaySVGEffectsGeometry::MoveBy(const nsPoint& aOffset)
nsCharClipGeometry::nsCharClipGeometry(nsCharClipDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
: nsDisplayItemGenericGeometry(aItem, aBuilder)
, mLeftEdge(aItem->mLeftEdge)
, mRightEdge(aItem->mRightEdge)
, mVisIStartEdge(aItem->mVisIStartEdge)
, mVisIEndEdge(aItem->mVisIEndEdge)
{}
nsDisplayTableItemGeometry::nsDisplayTableItemGeometry(nsDisplayTableItem* aItem,
+2 -2
View File
@@ -255,8 +255,8 @@ class nsCharClipGeometry : public nsDisplayItemGenericGeometry
public:
nsCharClipGeometry(nsCharClipDisplayItem* aItem, nsDisplayListBuilder* aBuilder);
nscoord mLeftEdge;
nscoord mRightEdge;
nscoord mVisIStartEdge;
nscoord mVisIEndEdge;
};
class nsDisplayTableItemGeometry
+13 -50
View File
@@ -3061,6 +3061,18 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram
TimeStamp startBuildDisplayList = TimeStamp::Now();
nsDisplayListBuilder builder(aFrame, nsDisplayListBuilder::PAINTING,
!(aFlags & PAINT_HIDE_CARET));
if (aFlags & PAINT_IN_TRANSFORM) {
builder.SetInTransform(true);
}
if (aFlags & PAINT_SYNC_DECODE_IMAGES) {
builder.SetSyncDecodeImages(true);
}
if (aFlags & (PAINT_WIDGET_LAYERS | PAINT_TO_WINDOW)) {
builder.SetPaintingToWindow(true);
}
if (aFlags & PAINT_IGNORE_SUPPRESSION) {
builder.IgnorePaintSuppression();
}
nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
bool usingDisplayPort = false;
@@ -3096,29 +3108,11 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram
visibleRegion = aDirtyRegion;
}
// If we're going to display something different from what we'd normally
// paint in a window then we will flush out any retained layer trees before
// *and after* we draw.
bool willFlushRetainedLayers = (aFlags & PAINT_HIDE_CARET) != 0;
nsDisplayList list;
if (aFlags & PAINT_IN_TRANSFORM) {
builder.SetInTransform(true);
}
if (aFlags & PAINT_SYNC_DECODE_IMAGES) {
builder.SetSyncDecodeImages(true);
}
if (aFlags & (PAINT_WIDGET_LAYERS | PAINT_TO_WINDOW)) {
builder.SetPaintingToWindow(true);
}
if (aFlags & PAINT_IGNORE_SUPPRESSION) {
builder.IgnorePaintSuppression();
}
// If the root has embedded plugins, flag the builder so we know we'll need
// to update plugin geometry after painting.
if ((aFlags & PAINT_WIDGET_LAYERS) &&
!willFlushRetainedLayers &&
!(aFlags & PAINT_DOCUMENT_RELATIVE) &&
rootPresContext->NeedToComputePluginGeometryUpdates()) {
builder.SetWillComputePluginGeometry(true);
@@ -3234,33 +3228,12 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram
buildingDisplayList(&builder, aFrame, canvasArea, false);
presShell->AddCanvasBackgroundColorItem(
builder, list, aFrame, canvasArea, aBackstop);
// If the passed in backstop color makes us draw something different from
// normal, we need to flush layers.
if ((aFlags & PAINT_WIDGET_LAYERS) && !willFlushRetainedLayers) {
nsView* view = aFrame->GetView();
if (view) {
nscolor backstop = presShell->ComputeBackstopColor(view);
// The PresShell's canvas background color doesn't get updated until
// EnterPresShell, so this check has to be done after that.
nscolor canvasColor = presShell->GetCanvasBackground();
if (NS_ComposeColors(aBackstop, canvasColor) !=
NS_ComposeColors(backstop, canvasColor)) {
willFlushRetainedLayers = true;
}
}
}
}
builder.LeavePresShell(aFrame);
Telemetry::AccumulateTimeDelta(Telemetry::PAINT_BUILD_DISPLAYLIST_TIME,
startBuildDisplayList);
if (builder.GetHadToIgnorePaintSuppression()) {
willFlushRetainedLayers = true;
}
bool profilerNeedsDisplayList = profiler_feature_active("displaylistdump");
bool consoleNeedsDisplayList = gfxUtils::DumpDisplayList() || gfxUtils::sDumpPainting;
#ifdef MOZ_DUMP_PAINTING
@@ -3304,16 +3277,7 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram
uint32_t flags = nsDisplayList::PAINT_DEFAULT;
if (aFlags & PAINT_WIDGET_LAYERS) {
flags |= nsDisplayList::PAINT_USE_WIDGET_LAYERS;
if (willFlushRetainedLayers) {
// The caller wanted to paint from retained layers, but set up
// the paint in such a way that we can't use them. We're going
// to display something different from what we'd normally paint
// in a window, so make sure we flush out any retained layer
// trees before *and after* we draw. Callers should be fixed to
// not do this.
NS_WARNING("Flushing retained layers!");
flags |= nsDisplayList::PAINT_FLUSH_LAYERS;
} else if (!(aFlags & PAINT_DOCUMENT_RELATIVE)) {
if (!(aFlags & PAINT_DOCUMENT_RELATIVE)) {
nsIWidget *widget = aFrame->GetNearestWidget();
if (widget) {
// If we're finished building display list items for painting of the outermost
@@ -3388,7 +3352,6 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram
// glass boundaries on Windows. Also set up the window dragging region
// and plugin clip regions and bounds.
if ((aFlags & PAINT_WIDGET_LAYERS) &&
!willFlushRetainedLayers &&
!(aFlags & PAINT_DOCUMENT_RELATIVE)) {
nsIWidget *widget = aFrame->GetNearestWidget();
if (widget) {
+2 -2
View File
@@ -690,14 +690,14 @@ TextOverflow::PruneDisplayListContents(nsDisplayList* aList,
aInsideMarkersArea.IStart(mBlockWM) - rect.IStart(mBlockWM);
if (istart > 0) {
(mBlockWM.IsBidiLTR() ?
charClip->mLeftEdge : charClip->mRightEdge) = istart;
charClip->mVisIStartEdge : charClip->mVisIEndEdge) = istart;
}
}
if (mIEnd.IsNeeded()) {
nscoord iend = rect.IEnd(mBlockWM) - aInsideMarkersArea.IEnd(mBlockWM);
if (iend > 0) {
(mBlockWM.IsBidiLTR() ?
charClip->mRightEdge : charClip->mLeftEdge) = iend;
charClip->mVisIEndEdge : charClip->mVisIStartEdge) = iend;
}
}
}
+2 -2
View File
@@ -184,8 +184,8 @@ class TextOverflow {
/**
* Clip or remove items given the final marker edges. ("clip" here just means
* assigning mLeftEdge/mRightEdge for any nsCharClipDisplayItem that needs it,
* see nsDisplayList.h for a description of that item).
* assigning mVisIStartEdge/mVisIEndEdge for any nsCharClipDisplayItem that
* needs it; see nsDisplayList.h for a description of that item).
* @param aFramesToHide remove display items for these frames
* @param aInsideMarkersArea is the area inside the markers
*/
+2 -32
View File
@@ -195,11 +195,10 @@ protected:
* We can also paint an "extra background color" behind the normal
* background.
*/
class nsDisplayCanvasBackgroundColor : public nsDisplayItem {
class nsDisplayCanvasBackgroundColor : public nsDisplaySolidColorBase {
public:
nsDisplayCanvasBackgroundColor(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame)
: nsDisplayItem(aBuilder, aFrame)
, mColor(NS_RGBA(0,0,0,0))
: nsDisplaySolidColorBase(aBuilder, aFrame, NS_RGBA(0,0,0,0))
{
}
@@ -208,19 +207,6 @@ public:
{
return NS_GET_A(mColor) > 0;
}
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap) override
{
if (NS_GET_A(mColor) == 255) {
return nsRegion(GetBounds(aBuilder, aSnap));
}
return nsRegion();
}
virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) override
{
*aColor = mColor;
return true;
}
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override
{
nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
@@ -234,19 +220,6 @@ public:
aOutFrames->AppendElement(mFrame);
}
virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override
{
return new nsDisplayItemBoundsGeometry(this, aBuilder);
}
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion) override
{
const nsDisplayItemBoundsGeometry* geometry = static_cast<const nsDisplayItemBoundsGeometry*>(aGeometry);
ComputeInvalidationRegionDifference(aBuilder, geometry, aInvalidRegion);
}
virtual void Paint(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx) override;
@@ -259,9 +232,6 @@ public:
#ifdef MOZ_DUMP_PAINTING
virtual void WriteDebugInfo(std::stringstream& aStream) override;
#endif
private:
nscolor mColor;
};
class nsDisplayCanvasBackgroundImage : public nsDisplayBackgroundImage {
+32 -30
View File
@@ -4655,8 +4655,8 @@ public:
nsRect newRect = geometry->mBounds;
nsRect oldRect = GetBounds(aBuilder, &snap);
if (decorations != geometry->mDecorations ||
mLeftEdge != geometry->mLeftEdge ||
mRightEdge != geometry->mRightEdge ||
mVisIStartEdge != geometry->mVisIStartEdge ||
mVisIEndEdge != geometry->mVisIEndEdge ||
!oldRect.IsEqualInterior(newRect) ||
!geometry->mBorderRect.IsEqualInterior(GetBorderRect())) {
aInvalidRegion->Or(oldRect, newRect);
@@ -4698,8 +4698,8 @@ nsDisplayText::Paint(nsDisplayListBuilder* aBuilder,
ctx->Rectangle(pixelVisible);
ctx->Clip();
NS_ASSERTION(mLeftEdge >= 0, "illegal left edge");
NS_ASSERTION(mRightEdge >= 0, "illegal right edge");
NS_ASSERTION(mVisIStartEdge >= 0, "illegal start edge");
NS_ASSERTION(mVisIEndEdge >= 0, "illegal end edge");
f->PaintText(aCtx, ToReferenceFrame(), extraVisible, *this);
}
@@ -5772,13 +5772,13 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx,
nsCSSShadowArray* shadow = textStyle->GetTextShadow();
GetSelectionTextShadow(this, type, aTextPaintStyle, &shadow);
if (shadow) {
nscoord leftEdge = iOffset;
nscoord startEdge = iOffset;
if (mTextRun->IsRightToLeft()) {
leftEdge -= mTextRun->GetAdvanceWidth(offset, length, &aProvider) +
startEdge -= mTextRun->GetAdvanceWidth(offset, length, &aProvider) +
hyphenWidth;
}
PaintShadows(shadow, offset, length, dirtyRect, aFramePt, textBaselinePt,
leftEdge, aProvider, foreground, aClipEdges, aCtx);
startEdge, aProvider, foreground, aClipEdges, aCtx);
}
// Draw text segment
@@ -6000,9 +6000,10 @@ ComputeTransformedLength(PropertyProvider& aProvider)
}
bool
nsTextFrame::MeasureCharClippedText(nscoord aLeftEdge, nscoord aRightEdge,
nscoord* aSnappedLeftEdge,
nscoord* aSnappedRightEdge)
nsTextFrame::MeasureCharClippedText(nscoord aVisIStartEdge,
nscoord aVisIEndEdge,
nscoord* aSnappedStartEdge,
nscoord* aSnappedEndEdge)
{
// We need a *reference* rendering context (not one that might have a
// transform), so we don't have a rendering context argument.
@@ -6017,9 +6018,9 @@ nsTextFrame::MeasureCharClippedText(nscoord aLeftEdge, nscoord aRightEdge,
uint32_t startOffset = provider.GetStart().GetSkippedOffset();
uint32_t maxLength = ComputeTransformedLength(provider);
return MeasureCharClippedText(provider, aLeftEdge, aRightEdge,
return MeasureCharClippedText(provider, aVisIStartEdge, aVisIEndEdge,
&startOffset, &maxLength,
aSnappedLeftEdge, aSnappedRightEdge);
aSnappedStartEdge, aSnappedEndEdge);
}
static uint32_t GetClusterLength(gfxTextRun* aTextRun,
@@ -6042,15 +6043,16 @@ static uint32_t GetClusterLength(gfxTextRun* aTextRun,
bool
nsTextFrame::MeasureCharClippedText(PropertyProvider& aProvider,
nscoord aLeftEdge, nscoord aRightEdge,
nscoord aVisIStartEdge,
nscoord aVisIEndEdge,
uint32_t* aStartOffset,
uint32_t* aMaxLength,
nscoord* aSnappedLeftEdge,
nscoord* aSnappedRightEdge)
nscoord* aSnappedStartEdge,
nscoord* aSnappedEndEdge)
{
*aSnappedLeftEdge = 0;
*aSnappedRightEdge = 0;
if (aLeftEdge <= 0 && aRightEdge <= 0) {
*aSnappedStartEdge = 0;
*aSnappedEndEdge = 0;
if (aVisIStartEdge <= 0 && aVisIEndEdge <= 0) {
return true;
}
@@ -6059,7 +6061,7 @@ nsTextFrame::MeasureCharClippedText(PropertyProvider& aProvider,
const nscoord frameISize = ISize();
const bool rtl = mTextRun->IsRightToLeft();
gfxFloat advanceWidth = 0;
const nscoord startEdge = rtl ? aRightEdge : aLeftEdge;
const nscoord startEdge = rtl ? aVisIEndEdge : aVisIStartEdge;
if (startEdge > 0) {
const gfxFloat maxAdvance = gfxFloat(startEdge);
while (maxLength > 0) {
@@ -6073,12 +6075,12 @@ nsTextFrame::MeasureCharClippedText(PropertyProvider& aProvider,
break;
}
}
nscoord* snappedStartEdge = rtl ? aSnappedRightEdge : aSnappedLeftEdge;
nscoord* snappedStartEdge = rtl ? aSnappedEndEdge : aSnappedStartEdge;
*snappedStartEdge = NSToCoordFloor(advanceWidth);
*aStartOffset = offset;
}
const nscoord endEdge = rtl ? aLeftEdge : aRightEdge;
const nscoord endEdge = rtl ? aVisIStartEdge : aVisIEndEdge;
if (endEdge > 0) {
const gfxFloat maxAdvance = gfxFloat(frameISize - endEdge);
while (maxLength > 0) {
@@ -6095,7 +6097,7 @@ nsTextFrame::MeasureCharClippedText(PropertyProvider& aProvider,
offset += clusterLength;
}
maxLength = offset - *aStartOffset;
nscoord* snappedEndEdge = rtl ? aSnappedLeftEdge : aSnappedRightEdge;
nscoord* snappedEndEdge = rtl ? aSnappedStartEdge : aSnappedEndEdge;
*snappedEndEdge = NSToCoordFloor(gfxFloat(frameISize) - advanceWidth);
}
*aMaxLength = maxLength;
@@ -6206,18 +6208,18 @@ nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
}
uint32_t startOffset = provider.GetStart().GetSkippedOffset();
uint32_t maxLength = ComputeTransformedLength(provider);
nscoord snappedLeftEdge, snappedRightEdge;
if (!MeasureCharClippedText(provider, aItem.mLeftEdge, aItem.mRightEdge,
&startOffset, &maxLength, &snappedLeftEdge, &snappedRightEdge)) {
nscoord snappedStartEdge, snappedEndEdge;
if (!MeasureCharClippedText(provider, aItem.mVisIStartEdge, aItem.mVisIEndEdge,
&startOffset, &maxLength, &snappedStartEdge, &snappedEndEdge)) {
return;
}
if (verticalRun) {
textBaselinePt.y += rtl ? -snappedRightEdge : snappedLeftEdge;
textBaselinePt.y += rtl ? -snappedEndEdge : snappedStartEdge;
} else {
textBaselinePt.x += rtl ? -snappedRightEdge : snappedLeftEdge;
textBaselinePt.x += rtl ? -snappedEndEdge : snappedStartEdge;
}
nsCharClipDisplayItem::ClipEdges clipEdges(aItem, snappedLeftEdge,
snappedRightEdge);
nsCharClipDisplayItem::ClipEdges clipEdges(aItem, snappedStartEdge,
snappedEndEdge);
nsTextPaintStyle textPaintStyle(this);
textPaintStyle.SetResolveColors(!aCallbacks);
@@ -6241,7 +6243,7 @@ nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
if (!aCallbacks) {
const nsStyleText* textStyle = StyleText();
PaintShadows(textStyle->mTextShadow, startOffset, maxLength,
aDirtyRect, framePt, textBaselinePt, snappedLeftEdge, provider,
aDirtyRect, framePt, textBaselinePt, snappedStartEdge, provider,
foregroundColor, clipEdges, ctx);
}
+10 -10
View File
@@ -303,15 +303,15 @@ public:
/**
* Calculate the horizontal bounds of the grapheme clusters that fit entirely
* inside the given left/right edges (which are positive lengths from the
* respective frame edge). If an input value is zero it is ignored and the
* result for that edge is zero. All out parameter values are undefined when
* the method returns false.
* inside the given left[top]/right[bottom] edges (which are positive lengths
* from the respective frame edge). If an input value is zero it is ignored
* and the result for that edge is zero. All out parameter values are
* undefined when the method returns false.
* @return true if at least one whole grapheme cluster fit between the edges
*/
bool MeasureCharClippedText(nscoord aLeftEdge, nscoord aRightEdge,
nscoord* aSnappedLeftEdge,
nscoord* aSnappedRightEdge);
bool MeasureCharClippedText(nscoord aVisIStartEdge, nscoord aVisIEndEdge,
nscoord* aSnappedStartEdge,
nscoord* aSnappedEndEdge);
/**
* Same as above; this method also the returns the corresponding text run
* offset and number of characters that fit. All out parameter values are
@@ -319,10 +319,10 @@ public:
* @return true if at least one whole grapheme cluster fit between the edges
*/
bool MeasureCharClippedText(PropertyProvider& aProvider,
nscoord aLeftEdge, nscoord aRightEdge,
nscoord aVisIStartEdge, nscoord aVisIEndEdge,
uint32_t* aStartOffset, uint32_t* aMaxLength,
nscoord* aSnappedLeftEdge,
nscoord* aSnappedRightEdge);
nscoord* aSnappedStartEdge,
nscoord* aSnappedEndEdge);
/**
* Object with various callbacks for PaintText() to invoke for different parts
+194 -87
View File
@@ -340,13 +340,17 @@ GetBaselinePosition(nsTextFrame* aFrame,
uint8_t aDominantBaseline,
float aFontSizeScaleFactor)
{
// use a dummy WritingMode, because nsTextFrame::GetLogicalBaseLine
// doesn't use it anyway
WritingMode writingMode;
WritingMode writingMode = aFrame->GetWritingMode();
gfxTextRun::Metrics metrics =
aTextRun->MeasureText(0, aTextRun->GetLength(), gfxFont::LOOSE_INK_EXTENTS,
nullptr, nullptr);
switch (aDominantBaseline) {
case NS_STYLE_DOMINANT_BASELINE_HANGING:
case NS_STYLE_DOMINANT_BASELINE_TEXT_BEFORE_EDGE:
return 0;
return writingMode.IsVerticalRL()
? metrics.mAscent + metrics.mDescent : 0;
case NS_STYLE_DOMINANT_BASELINE_USE_SCRIPT:
case NS_STYLE_DOMINANT_BASELINE_NO_CHANGE:
case NS_STYLE_DOMINANT_BASELINE_RESET_SIZE:
@@ -354,23 +358,24 @@ GetBaselinePosition(nsTextFrame* aFrame,
// support the complex baseline model that SVG 1.1 has and which
// css3-linebox now defines.
// (fall through)
case NS_STYLE_DOMINANT_BASELINE_AUTO:
case NS_STYLE_DOMINANT_BASELINE_ALPHABETIC:
return aFrame->GetLogicalBaseline(writingMode);
return writingMode.IsVerticalRL()
? metrics.mAscent + metrics.mDescent -
aFrame->GetLogicalBaseline(writingMode)
: aFrame->GetLogicalBaseline(writingMode);
case NS_STYLE_DOMINANT_BASELINE_MIDDLE:
return aFrame->GetLogicalBaseline(writingMode) -
SVGContentUtils::GetFontXHeight(aFrame) / 2.0 *
aFrame->PresContext()->AppUnitsPerCSSPixel() * aFontSizeScaleFactor;
}
gfxTextRun::Metrics metrics =
aTextRun->MeasureText(0, aTextRun->GetLength(), gfxFont::LOOSE_INK_EXTENTS,
nullptr, nullptr);
switch (aDominantBaseline) {
case NS_STYLE_DOMINANT_BASELINE_TEXT_AFTER_EDGE:
case NS_STYLE_DOMINANT_BASELINE_IDEOGRAPHIC:
return metrics.mAscent + metrics.mDescent;
return writingMode.IsVerticalLR()
? 0 : metrics.mAscent + metrics.mDescent;
case NS_STYLE_DOMINANT_BASELINE_CENTRAL:
case NS_STYLE_DOMINANT_BASELINE_MATHEMATICAL:
return (metrics.mAscent + metrics.mDescent) / 2.0;
@@ -526,6 +531,14 @@ struct TextRenderedRun
return GetTextRun()->IsRightToLeft();
}
/**
* Returns whether this rendered run is vertical.
*/
bool IsVertical() const
{
return GetTextRun()->IsVertical();
}
/**
* Returns the transform that converts from a <text> element's user space into
* the coordinate space that rendered runs can be painted directly in.
@@ -720,7 +733,7 @@ struct TextRenderedRun
* a selection mechanism for which glyphs will be painted, rather
* than a geometric clip.
*/
void GetClipEdges(nscoord& aLeftEdge, nscoord& aRightEdge) const;
void GetClipEdges(nscoord& aVisIStartEdge, nscoord& aVisIEndEdge) const;
/**
* Returns the advance width of the whole rendered run.
@@ -746,8 +759,12 @@ struct TextRenderedRun
/**
* The point in user space that the text is positioned at.
*
* For a horizontal run:
* The x coordinate is the left edge of a LTR run of text or the right edge of
* an RTL run. The y coordinate is the baseline of the text.
* For a vertical run:
* The x coordinate is the baseline of the text.
* The y coordinate is the top edge of a LTR run, or bottom of RTL.
*/
gfxPoint mPosition;
@@ -770,7 +787,7 @@ struct TextRenderedRun
/**
* The baseline in app units of this text run. The measurement is from the
* top of the text frame.
* top of the text frame. (From the left edge if vertical.)
*/
nscoord mBaseline;
@@ -816,10 +833,18 @@ TextRenderedRun::GetTransformFromUserSpaceForPainting(
m.Scale(mLengthAdjustScaleFactor, 1.0);
// Translation to get the text frame in the right place.
nsPoint t(IsRightToLeft() ?
-mFrame->GetRect().width + aItem.mRightEdge :
-aItem.mLeftEdge,
-mBaseline);
nsPoint t;
if (IsVertical()) {
t = nsPoint(-mBaseline,
IsRightToLeft()
? -mFrame->GetRect().height + aItem.mVisIEndEdge
: -aItem.mVisIStartEdge);
} else {
t = nsPoint(IsRightToLeft()
? -mFrame->GetRect().width + aItem.mVisIEndEdge
: -aItem.mVisIStartEdge,
-mBaseline);
}
m.Translate(AppUnitsToGfxUnits(t, aContext));
return m;
@@ -837,8 +862,8 @@ TextRenderedRun::GetTransformFromRunUserSpaceToUserSpace(
float cssPxPerDevPx = aContext->
AppUnitsToFloatCSSPixels(aContext->AppUnitsPerDevPixel());
nscoord left, right;
GetClipEdges(left, right);
nscoord start, end;
GetClipEdges(start, end);
// Glyph position in user space.
m.Translate(mPosition);
@@ -850,10 +875,18 @@ TextRenderedRun::GetTransformFromRunUserSpaceToUserSpace(
m.Scale(mLengthAdjustScaleFactor, 1.0);
// Translation to get the text frame in the right place.
nsPoint t(IsRightToLeft() ?
-mFrame->GetRect().width + left + right :
0,
-mBaseline);
nsPoint t;
if (IsVertical()) {
t = nsPoint(-mBaseline,
IsRightToLeft()
? -mFrame->GetRect().height + start + end
: 0);
} else {
t = nsPoint(IsRightToLeft()
? -mFrame->GetRect().width + start + end
: 0,
-mBaseline);
}
m.Translate(AppUnitsToGfxUnits(t, aContext) *
cssPxPerDevPx / mFontSizeScaleFactor);
@@ -869,13 +902,15 @@ TextRenderedRun::GetTransformFromRunUserSpaceToFrameUserSpace(
return m;
}
nscoord left, right;
GetClipEdges(left, right);
nscoord start, end;
GetClipEdges(start, end);
// Translate by the horizontal distance into the text frame this
// rendered run is.
return m.Translate(gfxPoint(gfxFloat(left) / aContext->AppUnitsPerCSSPixel(),
0));
gfxFloat appPerCssPx = aContext->AppUnitsPerCSSPixel();
gfxPoint t = IsVertical() ? gfxPoint(0, start / appPerCssPx)
: gfxPoint(start / appPerCssPx, 0);
return m.Translate(t);
}
SVGBBox
@@ -895,8 +930,10 @@ TextRenderedRun::GetRunUserSpaceRect(nsPresContext* aContext,
// horizontally.
nsRect self = mFrame->GetVisualOverflowRectRelativeToSelf();
nsRect rect = mFrame->GetRect();
nscoord above = -self.y;
nscoord below = self.YMost() - rect.height;
bool vertical = IsVertical();
nscoord above = vertical ? -self.x : -self.y;
nscoord below = vertical ? self.XMost() - rect.width
: self.YMost() - rect.height;
gfxSkipCharsIterator it = mFrame->EnsureTextRun(nsTextFrame::eInflated);
gfxTextRun* textRun = mFrame->GetTextRun(nsTextFrame::eInflated);
@@ -932,6 +969,11 @@ TextRenderedRun::GetRunUserSpaceRect(nsPresContext* aContext,
}
nsRect fillInAppUnits(x, baseline - above,
width, metrics.mBoundingBox.height + above + below);
if (textRun->IsVertical()) {
// Swap line-relative textMetrics dimensions to physical coordinates.
Swap(fillInAppUnits.x, fillInAppUnits.y);
Swap(fillInAppUnits.width, fillInAppUnits.height);
}
// Account for text-shadow.
if (aFlags & eIncludeTextShadow) {
@@ -949,7 +991,9 @@ TextRenderedRun::GetRunUserSpaceRect(nsPresContext* aContext,
// Scale the rectangle up due to any mFontSizeScaleFactor. We scale
// it around the text's origin.
ScaleAround(fill,
gfxPoint(0.0, aContext->AppUnitsToFloatCSSPixels(baseline)),
textRun->IsVertical()
? gfxPoint(aContext->AppUnitsToFloatCSSPixels(baseline), 0.0)
: gfxPoint(0.0, aContext->AppUnitsToFloatCSSPixels(baseline)),
1.0 / mFontSizeScaleFactor);
// Include the fill if requested.
@@ -997,15 +1041,16 @@ TextRenderedRun::GetUserSpaceRect(nsPresContext* aContext,
}
void
TextRenderedRun::GetClipEdges(nscoord& aLeftEdge, nscoord& aRightEdge) const
TextRenderedRun::GetClipEdges(nscoord& aVisIStartEdge,
nscoord& aVisIEndEdge) const
{
uint32_t contentLength = mFrame->GetContentLength();
if (mTextFrameContentOffset == 0 &&
mTextFrameContentLength == contentLength) {
// If the rendered run covers the entire content, we know we don't need
// to clip without having to measure anything.
aLeftEdge = 0;
aRightEdge = 0;
aVisIStartEdge = 0;
aVisIEndEdge = 0;
return;
}
@@ -1035,22 +1080,22 @@ TextRenderedRun::GetClipEdges(nscoord& aLeftEdge, nscoord& aRightEdge) const
// Measure the advance width in the text run between the start of
// frame's content and the start of the rendered run's content,
nscoord leftEdge =
nscoord startEdge =
textRun->GetAdvanceWidth(frameOffset, runOffset - frameOffset, nullptr);
// and between the end of the rendered run's content and the end
// of the frame's content.
nscoord rightEdge =
nscoord endEdge =
textRun->GetAdvanceWidth(runOffset + runLength,
frameOffset + frameLength - (runOffset + runLength),
nullptr);
if (textRun->IsRightToLeft()) {
aLeftEdge = rightEdge;
aRightEdge = leftEdge;
aVisIStartEdge = endEdge;
aVisIEndEdge = startEdge;
} else {
aLeftEdge = leftEdge;
aRightEdge = rightEdge;
aVisIStartEdge = startEdge;
aVisIEndEdge = endEdge;
}
}
@@ -1091,12 +1136,23 @@ TextRenderedRun::GetCharNumAtPosition(nsPresContext* aContext,
gfxFloat ascent, descent;
GetAscentAndDescentInAppUnits(mFrame, ascent, descent);
gfxFloat topEdge = mFrame->GetLogicalBaseline(mFrame->GetWritingMode()) - ascent;
gfxFloat bottomEdge = topEdge + ascent + descent;
if (p.y < aContext->AppUnitsToGfxUnits(topEdge) ||
p.y >= aContext->AppUnitsToGfxUnits(bottomEdge)) {
return -1;
WritingMode writingMode = mFrame->GetWritingMode();
if (writingMode.IsVertical()) {
gfxFloat leftEdge =
mFrame->GetLogicalBaseline(writingMode) -
(writingMode.IsVerticalRL() ? ascent : descent);
gfxFloat rightEdge = leftEdge + ascent + descent;
if (p.x < aContext->AppUnitsToGfxUnits(leftEdge) ||
p.x > aContext->AppUnitsToGfxUnits(rightEdge)) {
return -1;
}
} else {
gfxFloat topEdge = mFrame->GetLogicalBaseline(writingMode) - ascent;
gfxFloat bottomEdge = topEdge + ascent + descent;
if (p.y < aContext->AppUnitsToGfxUnits(topEdge) ||
p.y > aContext->AppUnitsToGfxUnits(bottomEdge)) {
return -1;
}
}
gfxSkipCharsIterator it = mFrame->EnsureTextRun(nsTextFrame::eInflated);
@@ -1111,7 +1167,8 @@ TextRenderedRun::GetCharNumAtPosition(nsPresContext* aContext,
aContext->AppUnitsToGfxUnits(textRun->GetAdvanceWidth(offset, length,
nullptr));
if (p.x < 0 || p.x >= runAdvance) {
gfxFloat pos = writingMode.IsVertical() ? p.y : p.x;
if (pos < 0 || pos >= runAdvance) {
return -1;
}
@@ -1124,8 +1181,8 @@ TextRenderedRun::GetCharNumAtPosition(nsPresContext* aContext,
gfxFloat advance =
aContext->AppUnitsToGfxUnits(textRun->GetAdvanceWidth(offset, length,
nullptr));
if ((rtl && p.x < runAdvance - advance) ||
(!rtl && p.x >= advance)) {
if ((rtl && pos < runAdvance - advance) ||
(!rtl && pos >= advance)) {
return i;
}
}
@@ -2684,7 +2741,7 @@ public:
explicit SVGCharClipDisplayItem(const TextRenderedRun& aRun)
: nsCharClipDisplayItem(aRun.mFrame)
{
aRun.GetClipEdges(mLeftEdge, mRightEdge);
aRun.GetClipEdges(mVisIStartEdge, mVisIEndEdge);
}
NS_DISPLAY_DECL_NAME("SVGText", TYPE_TEXT)
@@ -4325,9 +4382,18 @@ SVGTextFrame::GetExtentOfChar(nsIContent* aContent,
m.Rotate(mPositions[startIndex].mAngle);
m.Scale(1 / mFontSizeScaleFactor, 1 / mFontSizeScaleFactor);
gfxRect glyphRect
(x, -presContext->AppUnitsToGfxUnits(ascent) * cssPxPerDevPx,
advance, presContext->AppUnitsToGfxUnits(ascent + descent) * cssPxPerDevPx);
gfxRect glyphRect;
if (it.TextRun()->IsVertical()) {
glyphRect =
gfxRect(-presContext->AppUnitsToGfxUnits(descent) * cssPxPerDevPx, x,
presContext->AppUnitsToGfxUnits(ascent + descent) * cssPxPerDevPx,
advance);
} else {
glyphRect =
gfxRect(x, -presContext->AppUnitsToGfxUnits(ascent) * cssPxPerDevPx,
advance,
presContext->AppUnitsToGfxUnits(ascent + descent) * cssPxPerDevPx);
}
// Transform the glyph's rect into user space.
gfxRect r = m.TransformBounds(glyphRect);
@@ -4631,11 +4697,21 @@ SVGTextFrame::DetermineCharPositions(nsTArray<nsPoint>& aPositions)
// Reset the position to the new frame's position.
position = frit.Position();
if (textRun->IsRightToLeft()) {
position.x += frame->GetRect().width;
if (textRun->IsVertical()) {
if (textRun->IsRightToLeft()) {
position.y += frame->GetRect().height;
}
position.x += GetBaselinePosition(frame, textRun,
frit.DominantBaseline(),
mFontSizeScaleFactor);
} else {
if (textRun->IsRightToLeft()) {
position.x += frame->GetRect().width;
}
position.y += GetBaselinePosition(frame, textRun,
frit.DominantBaseline(),
mFontSizeScaleFactor);
}
position.y += GetBaselinePosition(frame, textRun, frit.DominantBaseline(),
mFontSizeScaleFactor);
// Any characters not in a frame, e.g. when display:none.
for (uint32_t i = 0; i < frit.UndisplayedCharacters(); i++) {
@@ -4658,7 +4734,8 @@ SVGTextFrame::DetermineCharPositions(nsTArray<nsPoint>& aPositions)
!textRun->IsClusterStart(it.GetSkippedOffset()))) {
nscoord advance = textRun->GetAdvanceWidth(it.GetSkippedOffset(), 1,
nullptr);
position.x += textRun->IsRightToLeft() ? -advance : advance;
(textRun->IsVertical() ? position.y : position.x) +=
textRun->IsRightToLeft() ? -advance : advance;
aPositions.AppendElement(lastPosition);
it.AdvanceOriginal(1);
}
@@ -4673,7 +4750,8 @@ SVGTextFrame::DetermineCharPositions(nsTArray<nsPoint>& aPositions)
uint32_t length = ClusterLength(textRun, it);
nscoord advance = textRun->GetAdvanceWidth(it.GetSkippedOffset(),
length, nullptr);
position.x += textRun->IsRightToLeft() ? -advance : advance;
(textRun->IsVertical() ? position.y : position.x) +=
textRun->IsRightToLeft() ? -advance : advance;
lastPosition = position;
}
it.AdvanceOriginal(1);
@@ -4716,42 +4794,51 @@ ConvertLogicalTextAnchorToPhysical(uint8_t aTextAnchor, bool aIsRightToLeft)
* character's initial position is the anchor point.
* @param aChunkEnd The character index just after the end of the anchored
* chunk.
* @param aLeftEdge The left-most edge of any of the glyphs within the
* anchored chunk.
* @param aRightEdge The right-most edge of any of the glyphs within the
* @param aVisIStartEdge The left/top-most edge of any of the glyphs within the
* anchored chunk.
* @param aVisIEndEdge The right/bottom-most edge of any of the glyphs within
* the anchored chunk.
* @param aAnchorSide The direction to anchor.
*/
static void
ShiftAnchoredChunk(nsTArray<mozilla::CharPosition>& aCharPositions,
uint32_t aChunkStart,
uint32_t aChunkEnd,
gfxFloat aLeftEdge,
gfxFloat aRightEdge,
TextAnchorSide aAnchorSide)
gfxFloat aVisIStartEdge,
gfxFloat aVisIEndEdge,
TextAnchorSide aAnchorSide,
bool aVertical)
{
NS_ASSERTION(aLeftEdge <= aRightEdge, "unexpected anchored chunk edges");
NS_ASSERTION(aChunkStart < aChunkEnd, "unexpected values for aChunkStart and "
"aChunkEnd");
NS_ASSERTION(aVisIStartEdge <= aVisIEndEdge,
"unexpected anchored chunk edges");
NS_ASSERTION(aChunkStart < aChunkEnd,
"unexpected values for aChunkStart and aChunkEnd");
gfxFloat shift = aCharPositions[aChunkStart].mPosition.x;
gfxFloat shift = aVertical ? aCharPositions[aChunkStart].mPosition.y
: aCharPositions[aChunkStart].mPosition.x;
switch (aAnchorSide) {
case eAnchorLeft:
shift -= aLeftEdge;
shift -= aVisIStartEdge;
break;
case eAnchorMiddle:
shift -= (aLeftEdge + aRightEdge) / 2;
shift -= (aVisIStartEdge + aVisIEndEdge) / 2;
break;
case eAnchorRight:
shift -= aRightEdge;
shift -= aVisIEndEdge;
break;
default:
NS_NOTREACHED("unexpected value for aAnchorSide");
}
if (shift != 0.0) {
for (uint32_t i = aChunkStart; i < aChunkEnd; i++) {
aCharPositions[i].mPosition.x += shift;
if (aVertical) {
for (uint32_t i = aChunkStart; i < aChunkEnd; i++) {
aCharPositions[i].mPosition.y += shift;
}
} else {
for (uint32_t i = aChunkStart; i < aChunkEnd; i++) {
aCharPositions[i].mPosition.x += shift;
}
}
}
}
@@ -4803,6 +4890,9 @@ SVGTextFrame::AdjustPositionsForClusters()
it.GetGlyphPartialAdvance(partLength, presContext) / mFontSizeScaleFactor;
gfxPoint direction = gfxPoint(cos(angle), sin(angle)) *
(it.TextRun()->IsRightToLeft() ? -1.0 : 1.0);
if (it.TextRun()->IsVertical()) {
Swap(direction.x, direction.y);
}
mPositions[charIndex].mPosition = mPositions[startIndex].mPosition +
direction * advance;
@@ -4945,7 +5035,10 @@ SVGTextFrame::DoTextPathLayout()
gfxFloat halfAdvance =
it.GetGlyphAdvance(context) / mFontSizeScaleFactor / 2.0;
gfxFloat sign = it.TextRun()->IsRightToLeft() ? -1.0 : 1.0;
gfxFloat midx = mPositions[i].mPosition.x + sign * halfAdvance + offset;
bool vertical = it.TextRun()->IsVertical();
gfxFloat midx = (vertical ? mPositions[i].mPosition.y
: 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;
@@ -4953,9 +5046,11 @@ SVGTextFrame::DoTextPathLayout()
// 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);
Float rotation = atan2f(tangent.y, tangent.x);
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 * mPositions[i].mPosition.y;
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;
@@ -4991,6 +5086,7 @@ SVGTextFrame::DoAnchoring()
it.Next();
}
bool vertical = GetWritingMode().IsVertical();
uint32_t start = it.TextElementCharIndex();
while (start < mPositions.Length()) {
it.AdvanceToCharacter(start);
@@ -5005,12 +5101,15 @@ SVGTextFrame::DoAnchoring()
do {
if (!it.IsOriginalCharSkipped() && !it.IsOriginalCharTrimmed()) {
gfxFloat advance = it.GetAdvance(presContext) / mFontSizeScaleFactor;
gfxFloat pos =
it.TextRun()->IsVertical() ? mPositions[index].mPosition.y
: mPositions[index].mPosition.x;
if (it.TextRun()->IsRightToLeft()) {
left = std::min(left, mPositions[index].mPosition.x - advance);
right = std::max(right, mPositions[index].mPosition.x);
left = std::min(left, pos - advance);
right = std::max(right, pos);
} else {
left = std::min(left, mPositions[index].mPosition.x);
right = std::max(right, mPositions[index].mPosition.x + advance);
left = std::min(left, pos);
right = std::max(right, pos + advance);
}
}
it.Next();
@@ -5024,7 +5123,8 @@ SVGTextFrame::DoAnchoring()
ConvertLogicalTextAnchorToPhysical(chunkFrame->StyleSVG()->mTextAnchor,
isRTL);
ShiftAnchoredChunk(mPositions, start, end, left, right, anchor);
ShiftAnchoredChunk(mPositions, start, end, left, right, anchor,
vertical);
}
start = it.TextElementCharIndex();
@@ -5095,6 +5195,7 @@ SVGTextFrame::DoGlyphPositioning()
}
nsPresContext* presContext = PresContext();
bool vertical = GetWritingMode().IsVertical();
float cssPxPerDevPx = presContext->
AppUnitsToFloatCSSPixels(presContext->AppUnitsPerDevPixel());
@@ -5105,9 +5206,10 @@ SVGTextFrame::DoGlyphPositioning()
double adjustment = 0.0;
mLengthAdjustScaleFactor = 1.0f;
if (adjustingTextLength) {
nscoord frameWidth = GetFirstPrincipalChild()->GetRect().width;
nscoord frameLength = vertical ? GetFirstPrincipalChild()->GetRect().height
: GetFirstPrincipalChild()->GetRect().width;
float actualTextLength =
static_cast<float>(presContext->AppUnitsToGfxUnits(frameWidth) * factor);
static_cast<float>(presContext->AppUnitsToGfxUnits(frameLength) * factor);
nsRefPtr<SVGAnimatedEnumeration> lengthAdjustEnum = element->LengthAdjust();
uint16_t lengthAdjust = lengthAdjustEnum->AnimVal();
@@ -5141,14 +5243,16 @@ SVGTextFrame::DoGlyphPositioning()
mPositions[0].mPosition += deltas[0];
}
gfxFloat xLengthAdjustFactor = vertical ? 1.0 : mLengthAdjustScaleFactor;
gfxFloat yLengthAdjustFactor = vertical ? mLengthAdjustScaleFactor : 1.0;
for (uint32_t i = 1; i < mPositions.Length(); i++) {
// Fill in unspecified x position.
if (!mPositions[i].IsXSpecified()) {
nscoord d = charPositions[i].x - charPositions[i - 1].x;
mPositions[i].mPosition.x =
mPositions[i - 1].mPosition.x +
presContext->AppUnitsToGfxUnits(d) * factor * mLengthAdjustScaleFactor;
if (!mPositions[i].mUnaddressable) {
presContext->AppUnitsToGfxUnits(d) * factor * xLengthAdjustFactor;
if (!vertical && !mPositions[i].mUnaddressable) {
mPositions[i].mPosition.x += adjustment;
}
}
@@ -5157,7 +5261,10 @@ SVGTextFrame::DoGlyphPositioning()
nscoord d = charPositions[i].y - charPositions[i - 1].y;
mPositions[i].mPosition.y =
mPositions[i - 1].mPosition.y +
presContext->AppUnitsToGfxUnits(d) * factor;
presContext->AppUnitsToGfxUnits(d) * factor * yLengthAdjustFactor;
if (vertical && !mPositions[i].mUnaddressable) {
mPositions[i].mPosition.y += adjustment;
}
}
// Add in dx/dy.
if (i < deltas.Length()) {