Bug 638937 - For text frames that are a child a floating first-letter frame, use the parent of the associated placeholder as the line-container to search. r=roc
authorMats Palmgren <matspal@gmail.com>
Wed, 22 Feb 2012 00:50:16 +0100
changeset 88873 0edd2447ab9bafb63f5904b36c8ef2eb882f5820
parent 88872 daceb968bf886f8e11c7c807678fdedc48ec8c7d
child 88874 f0c3fefb520af5822b0a71c0b7d5894d38e55ebe
push idunknown
push userunknown
push dateunknown
reviewersroc
bugs638937
milestone13.0a1
Bug 638937 - For text frames that are a child a floating first-letter frame, use the parent of the associated placeholder as the line-container to search. r=roc
layout/generic/crashtests/crashtests.list
layout/generic/crashtests/first-letter-638937-2.html
layout/generic/crashtests/first-letter-638937.html
layout/generic/nsFirstLetterFrame.cpp
layout/generic/nsFirstLetterFrame.h
layout/generic/nsTextFrame.h
layout/generic/nsTextFrameThebes.cpp
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -379,8 +379,10 @@ asserts-if(Android,8) load 673770.html
 load 679933-1.html
 load 682649-1.html
 load 683702-1.xhtml
 load 688996-1.html
 load 688996-2.html
 load 683712.html
 load text-overflow-bug713610.html
 load 700031.xhtml
+load first-letter-638937.html
+asserts(18) load first-letter-638937-2.html
new file mode 100644
--- /dev/null
+++ b/layout/generic/crashtests/first-letter-638937-2.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html style="height: 600em; -moz-column-width: 1px;">
+
+<head>
+<style>p::first-letter { float:left; }</style>
+</head>
+
+<body onload="x=document.body.parentNode; x.style.MozColumnWidth='111px'; x.offsetHeight; x.style.display='inline'; x.offsetHeight; "><p style="margin: -562949953421311em;">y
+</p><p>'</p></body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/generic/crashtests/first-letter-638937.html
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <title>yo-lobo</title>
+    <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" />
+    <meta content="werwolf - zoquete pluscuamperfecto" name="author" />
+    <style type="text/css">
+      body {
+        font-family: sans-serif, Arial;
+        -moz-column-count: 5;
+        -moz-column-gap: 1em;
+        padding: 5px;
+      }
+      body.crash {
+        -moz-column-rule-width: thin;
+        -moz-column-rule-style: solid;
+      }
+      p { 
+        margin: 10px;
+        padding: 0px;
+      }
+      p:first-letter { 
+        font-size: 30pt;
+        font-weight: bold;
+        float: left;
+        padding-right: 5px;
+        padding-bottom: 5px;
+      }
+    </style>
+    
+  </head>
+  <body onload="x=document.body; x.className='crash'">
+    <p>Lorem ipsum dolor sit amet consectetuer platea turpis justo Ut interdum. Wisi accumsan Vestibulum tempor vel ut nulla semper platea tincidunt consectetuer. Tristique metus ac nec turpis nibh nunc interdum ut tristique nec. Porttitor nibh sollicitudin urna fames non ultrices ipsum metus pede velit. Adipiscing amet et orci augue vel auctor amet ac Nam.</p>
+    <p>Ornare pellentesque augue leo Sed et In Donec nibh Cum tincidunt. Rutrum vel eget sagittis arcu cursus nibh Nam feugiat lacus lobortis. Suspendisse dictumst at Phasellus eu cursus sem risus dolor adipiscing metus. Lorem et Praesent Nunc Morbi Curabitur id pretium neque quis consequat. Convallis laoreet Integer et et Nulla In et et ut et. Convallis gravida ut tortor odio.</p>
+    <p>Fames pharetra et lacinia a aliquet tempor Vivamus Curabitur Vestibulum Vivamus. Duis Vestibulum nascetur sodales interdum congue a diam Lorem id In. Pede Curabitur interdum vitae nisl nunc est et ac Nulla quis. Sodales metus vitae mauris tellus Curabitur vitae dolor mauris wisi Phasellus. Pellentesque a Ut sem sapien interdum convallis Curabitur purus Aenean.</p>
+    <p>Ultrices pellentesque pretium odio vestibulum natoque natoque gravida Vivamus quis Integer. Ipsum cursus id nec cursus odio amet Vestibulum Suspendisse vitae habitasse. Leo elit eros porta volutpat laoreet commodo elit id egestas et. Curabitur arcu semper dictumst molestie Integer ligula id tellus quis Mauris. Tincidunt eget Sed amet justo porttitor egestas nibh pulvinar mauris justo. Vestibulum natoque eget hendrerit habitasse hendrerit eu purus Proin.</p>
+    <p>Lacinia Integer nec enim sem pellentesque sollicitudin sagittis Cras Sed Morbi. Vitae quis et consectetuer libero metus eros neque malesuada lacus justo. Curabitur ipsum lobortis massa lobortis consequat ut et Fusce quam augue. Laoreet id libero laoreet Curabitur interdum tempus Quisque elit amet purus. Libero sed Phasellus nec odio pede sed ac velit tincidunt id. Metus natoque.</p>
+    <p>Felis et enim at condimentum augue ut vitae In Mauris laoreet. Neque urna Morbi sapien risus nulla leo nec sed ipsum id. Id dictum eu natoque libero ac dapibus Ut sed ut dictum. Sed quis aliquet nunc vestibulum eleifend orci vestibulum Vestibulum Vivamus est. Et urna tempus montes eget Sed tristique.</p>
+    <p>Nibh id mauris ipsum Curabitur Integer velit sed Vivamus Integer laoreet. Eu semper Nulla ac Curabitur Vestibulum ut urna Sed libero In. Phasellus vitae nibh nunc eget Nam iaculis sed Phasellus mauris consectetuer. Amet dignissim natoque eget facilisi Vestibulum facilisis sit scelerisque porta adipiscing. Condimentum vel nec turpis metus est felis neque fames dapibus at. Aenean sed ac.</p>
+    <p>Malesuada hendrerit facilisis et Donec sed pellentesque Nullam est Praesent augue. Pede id orci tincidunt purus Suspendisse Vestibulum sagittis euismod sem porttitor. Lorem a convallis vestibulum condimentum Vestibulum mauris pellentesque consequat metus Vivamus. Consectetuer egestas eu Vestibulum id Morbi interdum montes eros odio Sed. Arcu Donec lacinia mauris vel tortor interdum in habitasse.</p>
+    <p>A scelerisque justo justo Vivamus eleifend velit Nullam orci tortor Nam. Nonummy ut nibh Pellentesque at pede Integer nibh metus justo scelerisque. Tincidunt consequat Curabitur porta non Morbi tincidunt egestas semper pellentesque Vestibulum. Ultrices congue In nec quis et pellentesque at vitae ipsum ridiculus. Elit fringilla ante Aenean elit Sed ut Nam pretium Aenean vel. Eu justo porta mauris congue neque pretium quis enim turpis sit. Auctor.</p>
+    <p>Scelerisque Maecenas Nunc lacinia porttitor fames Pellentesque sed urna Quisque pellentesque. Aenean eget tempus Praesent feugiat sed pretium dignissim In sapien Morbi. Velit mauris Nam Donec sollicitudin at vel mattis vitae amet laoreet. Vel at Nulla id Fusce vel interdum pellentesque Curabitur montes Phasellus. Accumsan interdum est eu ac lacus pellentesque sed Pellentesque.</p>
+</body>
+</html>
--- a/layout/generic/nsFirstLetterFrame.cpp
+++ b/layout/generic/nsFirstLetterFrame.cpp
@@ -295,17 +295,17 @@ nsFirstLetterFrame::Reflow(nsPresContext
         // Remove all of the childs next-in-flows
         static_cast<nsContainerFrame*>(kidNextInFlow->GetParent())
           ->DeleteNextInFlowChild(aPresContext, kidNextInFlow, true);
       }
     }
     else {
       // Create a continuation for the child frame if it doesn't already
       // have one.
-      if (!GetStyleDisplay()->IsFloating()) {
+      if (!IsFloating()) {
         nsIFrame* nextInFlow;
         rv = CreateNextInFlow(aPresContext, kid, nextInFlow);
         if (NS_FAILED(rv)) {
           return rv;
         }
     
         // And then push it to our overflow list
         const nsFrameList& overflow = mFrames.RemoveFramesAfter(kid);
@@ -337,17 +337,17 @@ nsFirstLetterFrame::CanContinueTextRun()
 }
 
 nsresult
 nsFirstLetterFrame::CreateContinuationForFloatingParent(nsPresContext* aPresContext,
                                                         nsIFrame* aChild,
                                                         nsIFrame** aContinuation,
                                                         bool aIsFluid)
 {
-  NS_ASSERTION(GetStyleDisplay()->IsFloating(),
+  NS_ASSERTION(IsFloating(),
                "can only call this on floating first letter frames");
   NS_PRECONDITION(aContinuation, "bad args");
 
   *aContinuation = nsnull;
   nsresult rv = NS_OK;
 
   nsIPresShell* presShell = aPresContext->PresShell();
   nsPlaceholderFrame* placeholderFrame =
--- a/layout/generic/nsFirstLetterFrame.h
+++ b/layout/generic/nsFirstLetterFrame.h
@@ -59,19 +59,21 @@ public:
                   nsIFrame*        aPrevInFlow);
   NS_IMETHOD SetInitialChildList(ChildListID     aListID,
                                  nsFrameList&    aChildList);
 #ifdef NS_DEBUG
   NS_IMETHOD GetFrameName(nsAString& aResult) const;
 #endif
   virtual nsIAtom* GetType() const;
 
+  bool IsFloating() const { return GetStateBits() & NS_FRAME_OUT_OF_FLOW; }
+
   virtual bool IsFrameOfType(PRUint32 aFlags) const
   {
-    if (!GetStyleDisplay()->IsFloating())
+    if (!IsFloating())
       aFlags = aFlags & ~(nsIFrame::eLineParticipant);
     return nsContainerFrame::IsFrameOfType(aFlags &
       ~(nsIFrame::eBidiInlineContainer));
   }
 
   virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext);
   virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext);
   virtual void AddInlineMinWidth(nsRenderingContext *aRenderingContext,
--- a/layout/generic/nsTextFrame.h
+++ b/layout/generic/nsTextFrame.h
@@ -452,16 +452,18 @@ public:
   TrimmedOffsets GetTrimmedOffsets(const nsTextFragment* aFrag,
                                    bool aTrimAfter);
 
   // Similar to Reflow(), but for use from nsLineLayout
   void ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
                   nsRenderingContext* aRenderingContext, bool aShouldBlink,
                   nsHTMLReflowMetrics& aMetrics, nsReflowStatus& aStatus);
 
+  bool IsFloatingFirstLetterChild() const;
+
 protected:
   virtual ~nsTextFrame();
 
   nsIFrame*   mNextContinuation;
   // The key invariant here is that mContentOffset never decreases along
   // a next-continuation chain. And of course mContentOffset is always <= the
   // the text node's content length, and the mContentOffset for the first frame
   // is always 0. Furthermore the text mapped by a frame is determined by
@@ -597,18 +599,16 @@ protected:
                 bool aDrawSoftHyphen,
                 const nscolor* const aDecorationOverrideColor = nsnull);
 
   // Set non empty rect to aRect, it should be overflow rect or frame rect.
   // If the result rect is larger than the given rect, this returns true.
   bool CombineSelectionUnderlineRect(nsPresContext* aPresContext,
                                        nsRect& aRect);
 
-  bool IsFloatingFirstLetterChild();
-
   ContentOffsets GetCharacterOffsetAtFramePointInternal(const nsPoint &aPoint,
                    bool aForInsertionPoint);
 
   void ClearFrameOffsetCache();
 
   virtual bool HasAnyNoncollapsedCharacters();
 
   void ClearMetrics(nsHTMLReflowMetrics& aMetrics);
--- a/layout/generic/nsTextFrameThebes.cpp
+++ b/layout/generic/nsTextFrameThebes.cpp
@@ -1163,18 +1163,23 @@ BuildTextRuns(gfxContext* aContext, nsTe
               const nsLineList::iterator* aForFrameLine,
               nsTextFrame::TextRunType aWhichTextRun, float aInflation)
 {
   NS_ASSERTION(aForFrame || aLineContainer,
                "One of aForFrame or aLineContainer must be set!");
   NS_ASSERTION(!aForFrameLine || aLineContainer,
                "line but no line container");
   
+  nsIFrame* lineContainerChild = aForFrame;
   if (!aLineContainer) {
-    aLineContainer = FindLineContainer(aForFrame);
+    if (aForFrame->IsFloatingFirstLetterChild()) {
+      lineContainerChild = aForFrame->PresContext()->PresShell()->
+        GetPlaceholderFrameFor(aForFrame->GetParent());
+    }
+    aLineContainer = FindLineContainer(lineContainerChild);
   } else {
     NS_ASSERTION(!aForFrame ||
                  (aLineContainer == FindLineContainer(aForFrame) ||
                   (aLineContainer->GetType() == nsGkAtoms::letterFrame &&
                    aLineContainer->GetStyleDisplay()->IsFloating())),
                  "Wrong line container hint");
   }
 
@@ -1197,24 +1202,24 @@ BuildTextRuns(gfxContext* aContext, nsTe
       child = child->GetNextSibling();
     }
     // Set mStartOfLine so FlushFrames knows its textrun ends a line
     scanner.SetAtStartOfLine();
     scanner.FlushFrames(true, false);
     return;
   }
 
-  // Find the line containing aForFrame
+  // Find the line containing 'lineContainerChild'.
 
   bool isValid = true;
   nsBlockInFlowLineIterator backIterator(block, &isValid);
   if (aForFrameLine) {
     backIterator = nsBlockInFlowLineIterator(block, *aForFrameLine, false);
   } else {
-    backIterator = nsBlockInFlowLineIterator(block, aForFrame, &isValid);
+    backIterator = nsBlockInFlowLineIterator(block, lineContainerChild, &isValid);
     NS_ASSERTION(isValid, "aForFrame not found in block, someone lied to us");
     NS_ASSERTION(backIterator.GetContainer() == block,
                  "Someone lied to us about the block");
   }
   nsBlockFrame::line_iterator startLine = backIterator.GetLine();
 
   // Find a line where we can start building text runs. We choose the last line
   // where:
@@ -1225,17 +1230,17 @@ BuildTextRuns(gfxContext* aContext, nsTe
   // on the textruns we construct).
   // The possibly-partial text runs up to and including the first space
   // are not reconstructed. We construct partial text runs for that text ---
   // for the sake of simplifying the code and feeding the linebreaker ---
   // but we discard them instead of assigning them to frames.
   // This is a little awkward because we traverse lines in the reverse direction
   // but we traverse the frames in each line in the forward direction.
   nsBlockInFlowLineIterator forwardIterator = backIterator;
-  nsTextFrame* stopAtFrame = aForFrame;
+  nsIFrame* stopAtFrame = lineContainerChild;
   nsTextFrame* nextLineFirstTextFrame = nsnull;
   bool seenTextRunBoundaryOnLaterLine = false;
   bool mayBeginInTextRun = true;
   while (true) {
     forwardIterator = backIterator;
     nsBlockFrame::line_iterator line = backIterator.GetLine();
     if (!backIterator.Prev() || backIterator.GetLine()->IsBlock()) {
       mayBeginInTextRun = false;
@@ -2061,22 +2066,20 @@ BuildTextRunsScanner::SetupLineBreakerCo
   userData->mMappedFlowCount = mMappedFlows.Length();
   userData->mLastFlowIndex = 0;
 
   PRUint32 nextBreakIndex = 0;
   nsTextFrame* nextBreakBeforeFrame = GetNextBreakBeforeFrame(&nextBreakIndex);
 
   PRUint32 i;
   const nsStyleText* textStyle = nsnull;
-  nsStyleContext* lastStyleContext = nsnull;
   for (i = 0; i < mMappedFlows.Length(); ++i) {
     MappedFlow* mappedFlow = &mMappedFlows[i];
     nsTextFrame* f = mappedFlow->mStartFrame;
 
-    lastStyleContext = f->GetStyleContext();
     textStyle = f->GetStyleText();
     nsTextFrameUtils::CompressionMode compression =
       CSSWhitespaceToCompressionMode[textStyle->mWhiteSpace];
 
     // Figure out what content is included in this flow.
     nsIContent* content = f->GetContent();
     const nsTextFragment* frag = content->GetText();
     PRInt32 contentStart = mappedFlow->mStartFrame->GetContentOffset();
@@ -7109,17 +7112,17 @@ nsTextFrame::SetLength(PRInt32 aLength, 
     f->GetContentLength(); // Assert if negative length
     f = static_cast<nsTextFrame*>(f->GetPrevContinuation());
     ++iterations;
   }
 #endif
 }
 
 bool
-nsTextFrame::IsFloatingFirstLetterChild()
+nsTextFrame::IsFloatingFirstLetterChild() const
 {
   if (!(GetStateBits() & TEXT_FIRST_LETTER))
     return false;
   nsIFrame* frame = GetParent();
   if (!frame || frame->GetType() != nsGkAtoms::letterFrame)
     return false;
   return frame->GetStyleDisplay()->IsFloating();
 }
@@ -8041,17 +8044,17 @@ nsTextFrame::List(FILE* out, PRInt32 aIn
   IndentBy(out, aIndent);
   ListTag(out);
   if (HasView()) {
     fprintf(out, " [view=%p]", static_cast<void*>(GetView()));
   }
   fprintf(out, " [run=%p]", static_cast<void*>(mTextRun));
 
   // Output the first/last content offset and prev/next in flow info
-  bool isComplete = GetContentEnd() == GetContent()->TextLength();
+  bool isComplete = PRUint32(GetContentEnd()) == GetContent()->TextLength();
   fprintf(out, "[%d,%d,%c] ", 
           GetContentOffset(), GetContentLength(),
           isComplete ? 'T':'F');
   
   if (GetNextSibling()) {
     fprintf(out, " next=%p", static_cast<void*>(GetNextSibling()));
   }
   nsIFrame* prevContinuation = GetPrevContinuation();