Commit f28f0d28 authored by Jonathan Watt's avatar Jonathan Watt
Browse files

Bug 1342951, part 3 - Support recording of SVGTextFrame correspondence before reflow. r=heycam

MozReview-Commit-ID: IG2etgpZCHN
parent 9d14ba56
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -5268,6 +5268,14 @@ nsBlockFrame::AppendFrames(ChildListID aListID,
  printf("\n");
#endif

  if (nsSVGUtils::IsInSVGTextSubtree(this)) {
    MOZ_ASSERT(GetParent()->IsSVGTextFrame(),
               "unexpected block frame in SVG text");
    // Workaround for bug 1399425 in case this bit has been removed from the
    // SVGTextFrame just before the parser adds more descendant nodes.
    GetParent()->AddStateBits(NS_STATE_SVG_TEXT_CORRESPONDENCE_DIRTY);
  }

  AddFrames(aFrameList, lastKid);
  if (aListID != kNoReflowPrincipalList) {
    PresContext()->PresShell()->
+4 −0
Original line number Diff line number Diff line
@@ -390,6 +390,10 @@ FRAME_STATE_BIT(SVG, 23, NS_STATE_SVG_POSITIONING_MAY_USE_PERCENTAGES)

FRAME_STATE_BIT(SVG, 24, NS_STATE_SVG_TEXT_IN_REFLOW)

// Set on SVGTextFrame frames when they need a
// TextNodeCorrespondenceRecorder::RecordCorrespondence call
// to update the cached nsTextNode indexes that they correspond to.
FRAME_STATE_BIT(SVG, 25, NS_STATE_SVG_TEXT_CORRESPONDENCE_DIRTY)

// == Frame state bits that apply to text frames ==============================

+32 −11
Original line number Diff line number Diff line
@@ -1392,8 +1392,13 @@ private:
/* static */ void
TextNodeCorrespondenceRecorder::RecordCorrespondence(SVGTextFrame* aRoot)
{
  if (aRoot->GetStateBits() & NS_STATE_SVG_TEXT_CORRESPONDENCE_DIRTY) {
    // Resolve bidi so that continuation frames are created if necessary:
    aRoot->MaybeResolveBidiForAnonymousBlockChild();
    TextNodeCorrespondenceRecorder recorder(aRoot);
    recorder.Record(aRoot);
    aRoot->RemoveStateBits(NS_STATE_SVG_TEXT_CORRESPONDENCE_DIRTY);
  }
}

void
@@ -1728,9 +1733,9 @@ private:
uint32_t
TextFrameIterator::UndisplayedCharacters() const
{
  MOZ_ASSERT(!(mRootFrame->PrincipalChildList().FirstChild() &&
               NS_SUBTREE_DIRTY(mRootFrame->PrincipalChildList().FirstChild())),
             "should have already reflowed the anonymous block child");
  MOZ_ASSERT(!(mRootFrame->GetStateBits() &
               NS_STATE_SVG_TEXT_CORRESPONDENCE_DIRTY),
             "Text correspondence must be up to date");

  if (!mCurrentFrame) {
    return mRootFrame->mTrailingUndisplayedCharacters;
@@ -2431,7 +2436,7 @@ CharIterator::CharIterator(SVGTextFrame* aSVGTextFrame,
                           nsIContent* aSubtree,
                           bool aPostReflow)
  : mFilter(aFilter),
    mFrameIterator(FrameIfAnonymousChildReflowed(aSVGTextFrame), aSubtree),
    mFrameIterator(aSVGTextFrame, aSubtree),
    mFrameForTrimCheck(nullptr),
    mTrimmedOffset(0),
    mTrimmedLength(0),
@@ -3779,7 +3784,9 @@ SVGTextFrame::ReflowSVG()
             "ReflowSVG mechanism not designed for this");

  if (!nsSVGUtils::NeedsReflowSVG(this)) {
    NS_ASSERTION(!(mState & NS_STATE_SVG_POSITIONING_DIRTY), "How did this happen?");
    MOZ_ASSERT(!HasAnyStateBits(NS_STATE_SVG_TEXT_CORRESPONDENCE_DIRTY |
                                NS_STATE_SVG_POSITIONING_DIRTY),
               "How did this happen?");
    return;
  }

@@ -5036,6 +5043,10 @@ SVGTextFrame::DoGlyphPositioning()
    return;
  }

  // Since we can be called directly via GetBBoxContribution, our correspondence
  // may not be up to date.
  TextNodeCorrespondenceRecorder::RecordCorrespondence(this);

  // Determine the positions of each character in app units.
  nsTArray<nsPoint> charPositions;
  DetermineCharPositions(charPositions);
@@ -5222,7 +5233,11 @@ SVGTextFrame::ScheduleReflowSVG()
void
SVGTextFrame::NotifyGlyphMetricsChange()
{
  AddStateBits(NS_STATE_SVG_POSITIONING_DIRTY);
  // TODO: perf - adding NS_STATE_SVG_TEXT_CORRESPONDENCE_DIRTY is overly
  // aggressive here.  Ideally we would only set that bit when our descendant
  // frame tree changes (i.e. after frame construction).
  AddStateBits(NS_STATE_SVG_TEXT_CORRESPONDENCE_DIRTY |
               NS_STATE_SVG_POSITIONING_DIRTY);
  nsLayoutUtils::PostRestyleEvent(
    mContent->AsElement(), nsRestyleHint(0),
    nsChangeHint_InvalidateRenderingObservers);
@@ -5274,6 +5289,9 @@ SVGTextFrame::MaybeReflowAnonymousBlockChild()
      // by nsSVGDisplayContainerFrame::ReflowSVG.)
      kid->AddStateBits(NS_FRAME_IS_DIRTY);
    }

    TextNodeCorrespondenceRecorder::RecordCorrespondence(this);

    MOZ_ASSERT(nsSVGUtils::AnyOuterSVGIsCallingReflowSVG(this),
               "should be under ReflowSVG");
    nsPresContext::InterruptPreventer noInterrupts(PresContext());
@@ -5286,7 +5304,12 @@ SVGTextFrame::DoReflow()
{
  // Since we are going to reflow the anonymous block frame, we will
  // need to update mPositions.
  AddStateBits(NS_STATE_SVG_POSITIONING_DIRTY);
  // We also mark our text correspondence as dirty since we can end up needing
  // reflow in ways that do not set NS_STATE_SVG_TEXT_CORRESPONDENCE_DIRTY.
  // (We'd then fail the "expected a TextNodeCorrespondenceProperty" assertion
  // when UpdateGlyphPositioning() is called after we return.)
  AddStateBits(NS_STATE_SVG_TEXT_CORRESPONDENCE_DIRTY |
               NS_STATE_SVG_POSITIONING_DIRTY);

  if (mState & NS_FRAME_IS_NONDISPLAY) {
    // Normally, these dirty flags would be cleared in ReflowSVG(), but that
@@ -5336,8 +5359,6 @@ SVGTextFrame::DoReflow()
  kid->SetSize(wm, desiredSize.Size(wm));

  RemoveStateBits(NS_STATE_SVG_TEXT_IN_REFLOW);

  TextNodeCorrespondenceRecorder::RecordCorrespondence(this);
}

// Usable font size range in devpixels / user-units
+2 −1
Original line number Diff line number Diff line
@@ -203,7 +203,8 @@ protected:
    , mLastContextScale(1.0f)
    , mLengthAdjustScaleFactor(1.0f)
  {
    AddStateBits(NS_STATE_SVG_POSITIONING_DIRTY);
    AddStateBits(NS_STATE_SVG_TEXT_CORRESPONDENCE_DIRTY |
                 NS_STATE_SVG_POSITIONING_DIRTY);
  }

  ~SVGTextFrame() {}