LCOV - code coverage report
Current view: directory - layout/base - nsLayoutUtils.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 2116 9 0.4 %
Date: 2012-06-02 Functions: 169 4 2.4 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* vim: set ts=2 sw=2 et tw=78: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is mozilla.org code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
      25                 :  *   Mats Palmgren <matspal@gmail.com>
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : #include "mozilla/Util.h"
      42                 : 
      43                 : #include "nsLayoutUtils.h"
      44                 : #include "nsIFormControlFrame.h"
      45                 : #include "nsPresContext.h"
      46                 : #include "nsIContent.h"
      47                 : #include "nsIDOMDocument.h"
      48                 : #include "nsIDOMHTMLDocument.h"
      49                 : #include "nsIDOMHTMLElement.h"
      50                 : #include "nsFrameList.h"
      51                 : #include "nsGkAtoms.h"
      52                 : #include "nsIAtom.h"
      53                 : #include "nsCSSPseudoElements.h"
      54                 : #include "nsCSSAnonBoxes.h"
      55                 : #include "nsCSSColorUtils.h"
      56                 : #include "nsIView.h"
      57                 : #include "nsPlaceholderFrame.h"
      58                 : #include "nsIScrollableFrame.h"
      59                 : #include "nsCSSFrameConstructor.h"
      60                 : #include "nsIPrivateDOMEvent.h"
      61                 : #include "nsIDOMEvent.h"
      62                 : #include "nsGUIEvent.h"
      63                 : #include "nsDisplayList.h"
      64                 : #include "nsRegion.h"
      65                 : #include "nsFrameManager.h"
      66                 : #include "nsBlockFrame.h"
      67                 : #include "nsBidiPresUtils.h"
      68                 : #include "imgIContainer.h"
      69                 : #include "gfxRect.h"
      70                 : #include "gfxContext.h"
      71                 : #include "gfxFont.h"
      72                 : #include "nsIInterfaceRequestorUtils.h"
      73                 : #include "nsCSSRendering.h"
      74                 : #include "nsContentUtils.h"
      75                 : #include "nsThemeConstants.h"
      76                 : #include "nsPIDOMWindow.h"
      77                 : #include "nsIBaseWindow.h"
      78                 : #include "nsIDocShell.h"
      79                 : #include "nsIDocShellTreeItem.h"
      80                 : #include "nsIWidget.h"
      81                 : #include "gfxMatrix.h"
      82                 : #include "gfxPoint3D.h"
      83                 : #include "gfxTypes.h"
      84                 : #include "gfxUserFontSet.h"
      85                 : #include "nsTArray.h"
      86                 : #include "nsHTMLCanvasElement.h"
      87                 : #include "nsICanvasRenderingContextInternal.h"
      88                 : #include "gfxPlatform.h"
      89                 : #include "nsClientRect.h"
      90                 : #ifdef MOZ_MEDIA
      91                 : #include "nsHTMLVideoElement.h"
      92                 : #endif
      93                 : #include "imgIRequest.h"
      94                 : #include "nsIImageLoadingContent.h"
      95                 : #include "nsCOMPtr.h"
      96                 : #include "nsListControlFrame.h"
      97                 : #include "ImageLayers.h"
      98                 : #include "mozilla/arm.h"
      99                 : #include "mozilla/dom/Element.h"
     100                 : #include "nsCanvasFrame.h"
     101                 : #include "gfxDrawable.h"
     102                 : #include "gfxUtils.h"
     103                 : #include "nsDataHashtable.h"
     104                 : #include "nsTextFrame.h"
     105                 : #include "nsFontFaceList.h"
     106                 : 
     107                 : #include "nsSVGUtils.h"
     108                 : #include "nsSVGIntegrationUtils.h"
     109                 : #include "nsSVGForeignObjectFrame.h"
     110                 : #include "nsSVGOuterSVGFrame.h"
     111                 : 
     112                 : #include "mozilla/Preferences.h"
     113                 : 
     114                 : #ifdef MOZ_XUL
     115                 : #include "nsXULPopupManager.h"
     116                 : #endif
     117                 : 
     118                 : #include "sampler.h"
     119                 : 
     120                 : using namespace mozilla;
     121                 : using namespace mozilla::layers;
     122                 : using namespace mozilla::dom;
     123                 : using namespace mozilla::layout;
     124                 : 
     125                 : #ifdef DEBUG
     126                 : // TODO: remove, see bug 598468.
     127                 : bool nsLayoutUtils::gPreventAssertInCompareTreePosition = false;
     128                 : #endif // DEBUG
     129                 : 
     130                 : typedef gfxPattern::GraphicsFilter GraphicsFilter;
     131                 : typedef FrameMetrics::ViewID ViewID;
     132                 : 
     133                 : static PRUint32 sFontSizeInflationEmPerLine;
     134                 : static PRUint32 sFontSizeInflationMinTwips;
     135                 : 
     136            1464 : static ViewID sScrollIdCounter = FrameMetrics::START_SCROLL_ID;
     137                 : 
     138                 : typedef nsDataHashtable<nsUint64HashKey, nsIContent*> ContentMap;
     139                 : static ContentMap* sContentMap = NULL;
     140               0 : static ContentMap& GetContentMap() {
     141               0 :   if (!sContentMap) {
     142               0 :     sContentMap = new ContentMap();
     143                 : #ifdef DEBUG
     144                 :     nsresult rv =
     145                 : #endif
     146               0 :     sContentMap->Init();
     147               0 :     NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "Could not initialize map.");
     148                 :   }
     149               0 :   return *sContentMap;
     150                 : }
     151                 : 
     152                 : 
     153                 : bool
     154               0 : nsLayoutUtils::Are3DTransformsEnabled()
     155                 : {
     156                 :   static bool s3DTransformsEnabled;
     157                 :   static bool s3DTransformPrefCached = false;
     158                 : 
     159               0 :   if (!s3DTransformPrefCached) {
     160               0 :     s3DTransformPrefCached = true;
     161                 :     mozilla::Preferences::AddBoolVarCache(&s3DTransformsEnabled, 
     162               0 :                                           "layout.3d-transforms.enabled");
     163                 :   }
     164                 : 
     165               0 :   return s3DTransformsEnabled;
     166                 : }
     167                 : 
     168                 : void
     169               0 : nsLayoutUtils::UnionChildOverflow(nsIFrame* aFrame,
     170                 :                                   nsOverflowAreas& aOverflowAreas)
     171                 : {
     172                 :   // Iterate over all children except pop-ups.
     173                 :   const nsIFrame::ChildListIDs skip(nsIFrame::kPopupList |
     174               0 :                                     nsIFrame::kSelectPopupList);
     175               0 :   for (nsIFrame::ChildListIterator childLists(aFrame);
     176               0 :        !childLists.IsDone(); childLists.Next()) {
     177               0 :     if (skip.Contains(childLists.CurrentID())) {
     178               0 :       continue;
     179                 :     }
     180                 : 
     181               0 :     nsFrameList children = childLists.CurrentList();
     182               0 :     for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) {
     183               0 :       nsIFrame* child = e.get();
     184                 :       nsOverflowAreas childOverflow =
     185               0 :         child->GetOverflowAreas() + child->GetPosition();
     186               0 :       aOverflowAreas.UnionWith(childOverflow);
     187                 :     }
     188                 :   }
     189               0 : }
     190                 : 
     191               0 : static void DestroyViewID(void* aObject, nsIAtom* aPropertyName,
     192                 :                           void* aPropertyValue, void* aData)
     193                 : {
     194               0 :   ViewID* id = static_cast<ViewID*>(aPropertyValue);
     195               0 :   GetContentMap().Remove(*id);
     196                 :   delete id;
     197               0 : }
     198                 : 
     199                 : /**
     200                 :  * A namespace class for static layout utilities.
     201                 :  */
     202                 : 
     203                 : ViewID
     204               0 : nsLayoutUtils::FindIDFor(nsIContent* aContent)
     205                 : {
     206                 :   ViewID scrollId;
     207                 : 
     208               0 :   void* scrollIdProperty = aContent->GetProperty(nsGkAtoms::RemoteId);
     209               0 :   if (scrollIdProperty) {
     210               0 :     scrollId = *static_cast<ViewID*>(scrollIdProperty);
     211                 :   } else {
     212               0 :     scrollId = sScrollIdCounter++;
     213                 :     aContent->SetProperty(nsGkAtoms::RemoteId, new ViewID(scrollId),
     214               0 :                           DestroyViewID);
     215               0 :     GetContentMap().Put(scrollId, aContent);
     216                 :   }
     217                 : 
     218               0 :   return scrollId;
     219                 : }
     220                 : 
     221                 : nsIContent*
     222               0 : nsLayoutUtils::FindContentFor(ViewID aId)
     223                 : {
     224               0 :   NS_ABORT_IF_FALSE(aId != FrameMetrics::NULL_SCROLL_ID &&
     225                 :                     aId != FrameMetrics::ROOT_SCROLL_ID,
     226                 :                     "Cannot find a content element in map for null or root IDs.");
     227                 :   nsIContent* content;
     228               0 :   bool exists = GetContentMap().Get(aId, &content);
     229                 : 
     230               0 :   if (exists) {
     231               0 :     return content;
     232                 :   } else {
     233               0 :     return nsnull;
     234                 :   }
     235                 : }
     236                 : 
     237                 : bool
     238               0 : nsLayoutUtils::GetDisplayPort(nsIContent* aContent, nsRect *aResult)
     239                 : {
     240               0 :   void* property = aContent->GetProperty(nsGkAtoms::DisplayPort);
     241               0 :   if (!property) {
     242               0 :     return false;
     243                 :   }
     244                 : 
     245               0 :   if (aResult) {
     246               0 :     *aResult = *static_cast<nsRect*>(property);
     247                 :   }
     248               0 :   return true;
     249                 : }
     250                 : 
     251                 : nsIFrame*
     252               0 : nsLayoutUtils::GetLastContinuationWithChild(nsIFrame* aFrame)
     253                 : {
     254               0 :   NS_PRECONDITION(aFrame, "NULL frame pointer");
     255               0 :   aFrame = aFrame->GetLastContinuation();
     256               0 :   while (!aFrame->GetFirstPrincipalChild() &&
     257               0 :          aFrame->GetPrevContinuation()) {
     258               0 :     aFrame = aFrame->GetPrevContinuation();
     259                 :   }
     260               0 :   return aFrame;
     261                 : }
     262                 : 
     263                 : /**
     264                 :  * GetFirstChildFrame returns the first "real" child frame of a
     265                 :  * given frame.  It will descend down into pseudo-frames (unless the
     266                 :  * pseudo-frame is the :before generated frame).
     267                 :  * @param aFrame the frame
     268                 :  * @param aFrame the frame's content node
     269                 :  */
     270                 : static nsIFrame*
     271               0 : GetFirstChildFrame(nsIFrame*       aFrame,
     272                 :                    nsIContent*     aContent)
     273                 : {
     274               0 :   NS_PRECONDITION(aFrame, "NULL frame pointer");
     275                 : 
     276                 :   // Get the first child frame
     277               0 :   nsIFrame* childFrame = aFrame->GetFirstPrincipalChild();
     278                 : 
     279                 :   // If the child frame is a pseudo-frame, then return its first child.
     280                 :   // Note that the frame we create for the generated content is also a
     281                 :   // pseudo-frame and so don't drill down in that case
     282               0 :   if (childFrame &&
     283               0 :       childFrame->IsPseudoFrame(aContent) &&
     284               0 :       !childFrame->IsGeneratedContentFrame()) {
     285               0 :     return GetFirstChildFrame(childFrame, aContent);
     286                 :   }
     287                 : 
     288               0 :   return childFrame;
     289                 : }
     290                 : 
     291                 : /**
     292                 :  * GetLastChildFrame returns the last "real" child frame of a
     293                 :  * given frame.  It will descend down into pseudo-frames (unless the
     294                 :  * pseudo-frame is the :after generated frame).
     295                 :  * @param aFrame the frame
     296                 :  * @param aFrame the frame's content node
     297                 :  */
     298                 : static nsIFrame*
     299               0 : GetLastChildFrame(nsIFrame*       aFrame,
     300                 :                   nsIContent*     aContent)
     301                 : {
     302               0 :   NS_PRECONDITION(aFrame, "NULL frame pointer");
     303                 : 
     304                 :   // Get the last continuation frame that's a parent
     305                 :   nsIFrame* lastParentContinuation =
     306               0 :     nsLayoutUtils::GetLastContinuationWithChild(aFrame);
     307                 :   nsIFrame* lastChildFrame =
     308               0 :     lastParentContinuation->GetLastChild(nsIFrame::kPrincipalList);
     309               0 :   if (lastChildFrame) {
     310                 :     // Get the frame's first continuation. This matters in case the frame has
     311                 :     // been continued across multiple lines or split by BiDi resolution.
     312               0 :     lastChildFrame = lastChildFrame->GetFirstContinuation();
     313                 : 
     314                 :     // If the last child frame is a pseudo-frame, then return its last child.
     315                 :     // Note that the frame we create for the generated content is also a
     316                 :     // pseudo-frame and so don't drill down in that case
     317               0 :     if (lastChildFrame &&
     318               0 :         lastChildFrame->IsPseudoFrame(aContent) &&
     319               0 :         !lastChildFrame->IsGeneratedContentFrame()) {
     320               0 :       return GetLastChildFrame(lastChildFrame, aContent);
     321                 :     }
     322                 : 
     323               0 :     return lastChildFrame;
     324                 :   }
     325                 : 
     326               0 :   return nsnull;
     327                 : }
     328                 : 
     329                 : //static
     330                 : nsIFrame::ChildListID
     331               0 : nsLayoutUtils::GetChildListNameFor(nsIFrame* aChildFrame)
     332                 : {
     333               0 :   nsIFrame::ChildListID id = nsIFrame::kPrincipalList;
     334                 : 
     335               0 :   if (aChildFrame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
     336               0 :     nsIFrame* pif = aChildFrame->GetPrevInFlow();
     337               0 :     if (pif->GetParent() == aChildFrame->GetParent()) {
     338               0 :       id = nsIFrame::kExcessOverflowContainersList;
     339                 :     }
     340                 :     else {
     341               0 :       id = nsIFrame::kOverflowContainersList;
     342                 :     }
     343                 :   }
     344                 :   // See if the frame is moved out of the flow
     345               0 :   else if (aChildFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
     346                 :     // Look at the style information to tell
     347               0 :     const nsStyleDisplay* disp = aChildFrame->GetStyleDisplay();
     348                 : 
     349               0 :     if (NS_STYLE_POSITION_ABSOLUTE == disp->mPosition) {
     350               0 :       id = nsIFrame::kAbsoluteList;
     351               0 :     } else if (NS_STYLE_POSITION_FIXED == disp->mPosition) {
     352               0 :       if (nsLayoutUtils::IsReallyFixedPos(aChildFrame)) {
     353               0 :         id = nsIFrame::kFixedList;
     354                 :       } else {
     355               0 :         id = nsIFrame::kAbsoluteList;
     356                 :       }
     357                 : #ifdef MOZ_XUL
     358               0 :     } else if (NS_STYLE_DISPLAY_POPUP == disp->mDisplay) {
     359                 :       // Out-of-flows that are DISPLAY_POPUP must be kids of the root popup set
     360                 : #ifdef DEBUG
     361               0 :       nsIFrame* parent = aChildFrame->GetParent();
     362               0 :       NS_ASSERTION(parent && parent->GetType() == nsGkAtoms::popupSetFrame,
     363                 :                    "Unexpected parent");
     364                 : #endif // DEBUG
     365                 : 
     366                 :       // XXX FIXME: Bug 350740
     367                 :       // Return here, because the postcondition for this function actually
     368                 :       // fails for this case, since the popups are not in a "real" frame list
     369                 :       // in the popup set.
     370               0 :       return nsIFrame::kPopupList;
     371                 : #endif // MOZ_XUL
     372                 :     } else {
     373               0 :       NS_ASSERTION(aChildFrame->GetStyleDisplay()->IsFloating(),
     374                 :                    "not a floated frame");
     375               0 :       id = nsIFrame::kFloatList;
     376                 :     }
     377                 : 
     378                 :   } else {
     379               0 :     nsIAtom* childType = aChildFrame->GetType();
     380               0 :     if (nsGkAtoms::menuPopupFrame == childType) {
     381               0 :       nsIFrame* parent = aChildFrame->GetParent();
     382                 :       nsIFrame* firstPopup = (parent)
     383                 :                              ? parent->GetFirstChild(nsIFrame::kPopupList)
     384               0 :                              : nsnull;
     385               0 :       NS_ASSERTION(!firstPopup || !firstPopup->GetNextSibling(),
     386                 :                    "We assume popupList only has one child, but it has more.");
     387                 :       id = firstPopup == aChildFrame
     388                 :              ? nsIFrame::kPopupList
     389               0 :              : nsIFrame::kPrincipalList;
     390               0 :     } else if (nsGkAtoms::tableColGroupFrame == childType) {
     391               0 :       id = nsIFrame::kColGroupList;
     392               0 :     } else if (nsGkAtoms::tableCaptionFrame == aChildFrame->GetType()) {
     393               0 :       id = nsIFrame::kCaptionList;
     394                 :     } else {
     395               0 :       id = nsIFrame::kPrincipalList;
     396                 :     }
     397                 :   }
     398                 : 
     399                 : #ifdef NS_DEBUG
     400                 :   // Verify that the frame is actually in that child list or in the
     401                 :   // corresponding overflow list.
     402               0 :   nsIFrame* parent = aChildFrame->GetParent();
     403               0 :   bool found = parent->GetChildList(id).ContainsFrame(aChildFrame);
     404               0 :   if (!found) {
     405               0 :     if (!(aChildFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
     406               0 :       found = parent->GetChildList(nsIFrame::kOverflowList)
     407               0 :                 .ContainsFrame(aChildFrame);
     408                 :     }
     409               0 :     else if (aChildFrame->GetStyleDisplay()->IsFloating()) {
     410               0 :       found = parent->GetChildList(nsIFrame::kOverflowOutOfFlowList)
     411               0 :                 .ContainsFrame(aChildFrame);
     412                 :     }
     413                 :     // else it's positioned and should have been on the 'id' child list.
     414               0 :     NS_POSTCONDITION(found, "not in child list");
     415                 :   }
     416                 : #endif
     417                 : 
     418               0 :   return id;
     419                 : }
     420                 : 
     421                 : // static
     422                 : nsIFrame*
     423               0 : nsLayoutUtils::GetBeforeFrame(nsIFrame* aFrame)
     424                 : {
     425               0 :   NS_PRECONDITION(aFrame, "NULL frame pointer");
     426               0 :   NS_ASSERTION(!aFrame->GetPrevContinuation(),
     427                 :                "aFrame must be first continuation");
     428                 : 
     429               0 :   nsIFrame* firstFrame = GetFirstChildFrame(aFrame, aFrame->GetContent());
     430                 : 
     431               0 :   if (firstFrame && IsGeneratedContentFor(nsnull, firstFrame,
     432               0 :                                           nsCSSPseudoElements::before)) {
     433               0 :     return firstFrame;
     434                 :   }
     435                 : 
     436               0 :   return nsnull;
     437                 : }
     438                 : 
     439                 : // static
     440                 : nsIFrame*
     441               0 : nsLayoutUtils::GetAfterFrame(nsIFrame* aFrame)
     442                 : {
     443               0 :   NS_PRECONDITION(aFrame, "NULL frame pointer");
     444                 : 
     445               0 :   nsIFrame* lastFrame = GetLastChildFrame(aFrame, aFrame->GetContent());
     446                 : 
     447               0 :   if (lastFrame && IsGeneratedContentFor(nsnull, lastFrame,
     448               0 :                                          nsCSSPseudoElements::after)) {
     449               0 :     return lastFrame;
     450                 :   }
     451                 : 
     452               0 :   return nsnull;
     453                 : }
     454                 : 
     455                 : // static
     456                 : nsIFrame*
     457               0 : nsLayoutUtils::GetClosestFrameOfType(nsIFrame* aFrame, nsIAtom* aFrameType)
     458                 : {
     459               0 :   for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) {
     460               0 :     if (frame->GetType() == aFrameType) {
     461               0 :       return frame;
     462                 :     }
     463                 :   }
     464               0 :   return nsnull;
     465                 : }
     466                 : 
     467                 : // static
     468                 : nsIFrame*
     469               0 : nsLayoutUtils::GetStyleFrame(nsIFrame* aFrame)
     470                 : {
     471               0 :   if (aFrame->GetType() == nsGkAtoms::tableOuterFrame) {
     472               0 :     nsIFrame* inner = aFrame->GetFirstPrincipalChild();
     473               0 :     NS_ASSERTION(inner, "Outer table must have an inner");
     474               0 :     return inner;
     475                 :   }
     476                 : 
     477               0 :   return aFrame;
     478                 : }
     479                 : 
     480                 : nsIFrame*
     481               0 : nsLayoutUtils::GetFloatFromPlaceholder(nsIFrame* aFrame) {
     482               0 :   NS_ASSERTION(nsGkAtoms::placeholderFrame == aFrame->GetType(),
     483                 :                "Must have a placeholder here");
     484               0 :   if (aFrame->GetStateBits() & PLACEHOLDER_FOR_FLOAT) {
     485                 :     nsIFrame *outOfFlowFrame =
     486               0 :       nsPlaceholderFrame::GetRealFrameForPlaceholder(aFrame);
     487               0 :     NS_ASSERTION(outOfFlowFrame->GetStyleDisplay()->IsFloating(),
     488                 :                  "How did that happen?");
     489               0 :     return outOfFlowFrame;
     490                 :   }
     491                 : 
     492               0 :   return nsnull;
     493                 : }
     494                 : 
     495                 : // static
     496                 : bool
     497               0 : nsLayoutUtils::IsGeneratedContentFor(nsIContent* aContent,
     498                 :                                      nsIFrame* aFrame,
     499                 :                                      nsIAtom* aPseudoElement)
     500                 : {
     501               0 :   NS_PRECONDITION(aFrame, "Must have a frame");
     502               0 :   NS_PRECONDITION(aPseudoElement, "Must have a pseudo name");
     503                 : 
     504               0 :   if (!aFrame->IsGeneratedContentFrame()) {
     505               0 :     return false;
     506                 :   }
     507               0 :   nsIFrame* parent = aFrame->GetParent();
     508               0 :   NS_ASSERTION(parent, "Generated content can't be root frame");
     509               0 :   if (parent->IsGeneratedContentFrame()) {
     510                 :     // Not the root of the generated content
     511               0 :     return false;
     512                 :   }
     513                 : 
     514               0 :   if (aContent && parent->GetContent() != aContent) {
     515               0 :     return false;
     516                 :   }
     517                 : 
     518               0 :   return (aFrame->GetContent()->Tag() == nsGkAtoms::mozgeneratedcontentbefore) ==
     519               0 :     (aPseudoElement == nsCSSPseudoElements::before);
     520                 : }
     521                 : 
     522                 : // static
     523                 : nsIFrame*
     524               0 : nsLayoutUtils::GetCrossDocParentFrame(const nsIFrame* aFrame,
     525                 :                                       nsPoint* aExtraOffset)
     526                 : {
     527               0 :   nsIFrame* p = aFrame->GetParent();
     528               0 :   if (p)
     529               0 :     return p;
     530                 : 
     531               0 :   nsIView* v = aFrame->GetView();
     532               0 :   if (!v)
     533               0 :     return nsnull;
     534               0 :   v = v->GetParent(); // anonymous inner view
     535               0 :   if (!v)
     536               0 :     return nsnull;
     537               0 :   if (aExtraOffset) {
     538               0 :     *aExtraOffset += v->GetPosition();
     539                 :   }
     540               0 :   v = v->GetParent(); // subdocumentframe's view
     541               0 :   return v ? v->GetFrame() : nsnull;
     542                 : }
     543                 : 
     544                 : // static
     545                 : bool
     546               0 : nsLayoutUtils::IsProperAncestorFrameCrossDoc(nsIFrame* aAncestorFrame, nsIFrame* aFrame,
     547                 :                                              nsIFrame* aCommonAncestor)
     548                 : {
     549               0 :   if (aFrame == aCommonAncestor)
     550               0 :     return false;
     551                 : 
     552               0 :   nsIFrame* parentFrame = GetCrossDocParentFrame(aFrame);
     553                 : 
     554               0 :   while (parentFrame != aCommonAncestor) {
     555               0 :     if (parentFrame == aAncestorFrame)
     556               0 :       return true;
     557                 : 
     558               0 :     parentFrame = GetCrossDocParentFrame(parentFrame);
     559                 :   }
     560                 : 
     561               0 :   return false;
     562                 : }
     563                 : 
     564                 : // static
     565                 : bool
     566               0 : nsLayoutUtils::IsAncestorFrameCrossDoc(nsIFrame* aAncestorFrame, nsIFrame* aFrame,
     567                 :                                        nsIFrame* aCommonAncestor)
     568                 : {
     569               0 :   if (aFrame == aAncestorFrame)
     570               0 :     return true;
     571               0 :   return IsProperAncestorFrameCrossDoc(aAncestorFrame, aFrame, aCommonAncestor);
     572                 : }
     573                 : 
     574                 : // static
     575                 : bool
     576               0 : nsLayoutUtils::IsProperAncestorFrame(nsIFrame* aAncestorFrame, nsIFrame* aFrame,
     577                 :                                      nsIFrame* aCommonAncestor)
     578                 : {
     579               0 :   if (aFrame == aCommonAncestor) {
     580               0 :     return false;
     581                 :   }
     582                 : 
     583               0 :   nsIFrame* parentFrame = aFrame->GetParent();
     584                 : 
     585               0 :   while (parentFrame != aCommonAncestor) {
     586               0 :     if (parentFrame == aAncestorFrame) {
     587               0 :       return true;
     588                 :     }
     589                 : 
     590               0 :     parentFrame = parentFrame->GetParent();
     591                 :   }
     592                 : 
     593               0 :   return false;
     594                 : }
     595                 : 
     596                 : // static
     597                 : PRInt32
     598               0 : nsLayoutUtils::DoCompareTreePosition(nsIContent* aContent1,
     599                 :                                      nsIContent* aContent2,
     600                 :                                      PRInt32 aIf1Ancestor,
     601                 :                                      PRInt32 aIf2Ancestor,
     602                 :                                      const nsIContent* aCommonAncestor)
     603                 : {
     604               0 :   NS_PRECONDITION(aContent1, "aContent1 must not be null");
     605               0 :   NS_PRECONDITION(aContent2, "aContent2 must not be null");
     606                 : 
     607               0 :   nsAutoTArray<nsINode*, 32> content1Ancestors;
     608                 :   nsINode* c1;
     609               0 :   for (c1 = aContent1; c1 && c1 != aCommonAncestor; c1 = c1->GetNodeParent()) {
     610               0 :     content1Ancestors.AppendElement(c1);
     611                 :   }
     612               0 :   if (!c1 && aCommonAncestor) {
     613                 :     // So, it turns out aCommonAncestor was not an ancestor of c1. Oops.
     614                 :     // Never mind. We can continue as if aCommonAncestor was null.
     615               0 :     aCommonAncestor = nsnull;
     616                 :   }
     617                 : 
     618               0 :   nsAutoTArray<nsINode*, 32> content2Ancestors;
     619                 :   nsINode* c2;
     620               0 :   for (c2 = aContent2; c2 && c2 != aCommonAncestor; c2 = c2->GetNodeParent()) {
     621               0 :     content2Ancestors.AppendElement(c2);
     622                 :   }
     623               0 :   if (!c2 && aCommonAncestor) {
     624                 :     // So, it turns out aCommonAncestor was not an ancestor of c2.
     625                 :     // We need to retry with no common ancestor hint.
     626                 :     return DoCompareTreePosition(aContent1, aContent2,
     627               0 :                                  aIf1Ancestor, aIf2Ancestor, nsnull);
     628                 :   }
     629                 : 
     630               0 :   int last1 = content1Ancestors.Length() - 1;
     631               0 :   int last2 = content2Ancestors.Length() - 1;
     632               0 :   nsINode* content1Ancestor = nsnull;
     633               0 :   nsINode* content2Ancestor = nsnull;
     634               0 :   while (last1 >= 0 && last2 >= 0
     635               0 :          && ((content1Ancestor = content1Ancestors.ElementAt(last1)) ==
     636               0 :              (content2Ancestor = content2Ancestors.ElementAt(last2)))) {
     637               0 :     last1--;
     638               0 :     last2--;
     639                 :   }
     640                 : 
     641               0 :   if (last1 < 0) {
     642               0 :     if (last2 < 0) {
     643               0 :       NS_ASSERTION(aContent1 == aContent2, "internal error?");
     644               0 :       return 0;
     645                 :     }
     646                 :     // aContent1 is an ancestor of aContent2
     647               0 :     return aIf1Ancestor;
     648                 :   }
     649                 : 
     650               0 :   if (last2 < 0) {
     651                 :     // aContent2 is an ancestor of aContent1
     652               0 :     return aIf2Ancestor;
     653                 :   }
     654                 : 
     655                 :   // content1Ancestor != content2Ancestor, so they must be siblings with the same parent
     656               0 :   nsINode* parent = content1Ancestor->GetNodeParent();
     657                 : #ifdef DEBUG
     658                 :   // TODO: remove the uglyness, see bug 598468.
     659               0 :   NS_ASSERTION(gPreventAssertInCompareTreePosition || parent,
     660                 :                "no common ancestor at all???");
     661                 : #endif // DEBUG
     662               0 :   if (!parent) { // different documents??
     663               0 :     return 0;
     664                 :   }
     665                 : 
     666               0 :   PRInt32 index1 = parent->IndexOf(content1Ancestor);
     667               0 :   PRInt32 index2 = parent->IndexOf(content2Ancestor);
     668               0 :   if (index1 < 0 || index2 < 0) {
     669                 :     // one of them must be anonymous; we can't determine the order
     670               0 :     return 0;
     671                 :   }
     672                 : 
     673               0 :   return index1 - index2;
     674                 : }
     675                 : 
     676               0 : static nsIFrame* FillAncestors(nsIFrame* aFrame,
     677                 :                                nsIFrame* aStopAtAncestor, nsFrameManager* aFrameManager,
     678                 :                                nsTArray<nsIFrame*>* aAncestors)
     679                 : {
     680               0 :   while (aFrame && aFrame != aStopAtAncestor) {
     681               0 :     aAncestors->AppendElement(aFrame);
     682               0 :     aFrame = nsLayoutUtils::GetParentOrPlaceholderFor(aFrameManager, aFrame);
     683                 :   }
     684               0 :   return aFrame;
     685                 : }
     686                 : 
     687                 : // Return true if aFrame1 is after aFrame2
     688               0 : static bool IsFrameAfter(nsIFrame* aFrame1, nsIFrame* aFrame2)
     689                 : {
     690               0 :   nsIFrame* f = aFrame2;
     691               0 :   do {
     692               0 :     f = f->GetNextSibling();
     693               0 :     if (f == aFrame1)
     694               0 :       return true;
     695                 :   } while (f);
     696               0 :   return false;
     697                 : }
     698                 : 
     699                 : // static
     700                 : PRInt32
     701               0 : nsLayoutUtils::DoCompareTreePosition(nsIFrame* aFrame1,
     702                 :                                      nsIFrame* aFrame2,
     703                 :                                      PRInt32 aIf1Ancestor,
     704                 :                                      PRInt32 aIf2Ancestor,
     705                 :                                      nsIFrame* aCommonAncestor)
     706                 : {
     707               0 :   NS_PRECONDITION(aFrame1, "aFrame1 must not be null");
     708               0 :   NS_PRECONDITION(aFrame2, "aFrame2 must not be null");
     709                 : 
     710               0 :   nsPresContext* presContext = aFrame1->PresContext();
     711               0 :   if (presContext != aFrame2->PresContext()) {
     712               0 :     NS_ERROR("no common ancestor at all, different documents");
     713               0 :     return 0;
     714                 :   }
     715               0 :   nsFrameManager* frameManager = presContext->PresShell()->FrameManager();
     716                 : 
     717               0 :   nsAutoTArray<nsIFrame*,20> frame1Ancestors;
     718               0 :   if (!FillAncestors(aFrame1, aCommonAncestor, frameManager, &frame1Ancestors)) {
     719                 :     // We reached the root of the frame tree ... if aCommonAncestor was set,
     720                 :     // it is wrong
     721               0 :     aCommonAncestor = nsnull;
     722                 :   }
     723                 : 
     724               0 :   nsAutoTArray<nsIFrame*,20> frame2Ancestors;
     725               0 :   if (!FillAncestors(aFrame2, aCommonAncestor, frameManager, &frame2Ancestors) &&
     726                 :       aCommonAncestor) {
     727                 :     // We reached the root of the frame tree ... aCommonAncestor was wrong.
     728                 :     // Try again with no hint.
     729                 :     return DoCompareTreePosition(aFrame1, aFrame2,
     730               0 :                                  aIf1Ancestor, aIf2Ancestor, nsnull);
     731                 :   }
     732                 : 
     733               0 :   PRInt32 last1 = PRInt32(frame1Ancestors.Length()) - 1;
     734               0 :   PRInt32 last2 = PRInt32(frame2Ancestors.Length()) - 1;
     735               0 :   while (last1 >= 0 && last2 >= 0 &&
     736               0 :          frame1Ancestors[last1] == frame2Ancestors[last2]) {
     737               0 :     last1--;
     738               0 :     last2--;
     739                 :   }
     740                 : 
     741               0 :   if (last1 < 0) {
     742               0 :     if (last2 < 0) {
     743               0 :       NS_ASSERTION(aFrame1 == aFrame2, "internal error?");
     744               0 :       return 0;
     745                 :     }
     746                 :     // aFrame1 is an ancestor of aFrame2
     747               0 :     return aIf1Ancestor;
     748                 :   }
     749                 : 
     750               0 :   if (last2 < 0) {
     751                 :     // aFrame2 is an ancestor of aFrame1
     752               0 :     return aIf2Ancestor;
     753                 :   }
     754                 : 
     755               0 :   nsIFrame* ancestor1 = frame1Ancestors[last1];
     756               0 :   nsIFrame* ancestor2 = frame2Ancestors[last2];
     757                 :   // Now we should be able to walk sibling chains to find which one is first
     758               0 :   if (IsFrameAfter(ancestor2, ancestor1))
     759               0 :     return -1;
     760               0 :   if (IsFrameAfter(ancestor1, ancestor2))
     761               0 :     return 1;
     762               0 :   NS_WARNING("Frames were in different child lists???");
     763               0 :   return 0;
     764                 : }
     765                 : 
     766                 : // static
     767               0 : nsIFrame* nsLayoutUtils::GetLastSibling(nsIFrame* aFrame) {
     768               0 :   if (!aFrame) {
     769               0 :     return nsnull;
     770                 :   }
     771                 : 
     772                 :   nsIFrame* next;
     773               0 :   while ((next = aFrame->GetNextSibling()) != nsnull) {
     774               0 :     aFrame = next;
     775                 :   }
     776               0 :   return aFrame;
     777                 : }
     778                 : 
     779                 : // static
     780                 : nsIView*
     781               0 : nsLayoutUtils::FindSiblingViewFor(nsIView* aParentView, nsIFrame* aFrame) {
     782               0 :   nsIFrame* parentViewFrame = aParentView->GetFrame();
     783               0 :   nsIContent* parentViewContent = parentViewFrame ? parentViewFrame->GetContent() : nsnull;
     784               0 :   for (nsIView* insertBefore = aParentView->GetFirstChild(); insertBefore;
     785                 :        insertBefore = insertBefore->GetNextSibling()) {
     786               0 :     nsIFrame* f = insertBefore->GetFrame();
     787               0 :     if (!f) {
     788                 :       // this view could be some anonymous view attached to a meaningful parent
     789               0 :       for (nsIView* searchView = insertBefore->GetParent(); searchView;
     790                 :            searchView = searchView->GetParent()) {
     791               0 :         f = searchView->GetFrame();
     792               0 :         if (f) {
     793               0 :           break;
     794                 :         }
     795                 :       }
     796               0 :       NS_ASSERTION(f, "Can't find a frame anywhere!");
     797                 :     }
     798               0 :     if (!f || !aFrame->GetContent() || !f->GetContent() ||
     799               0 :         CompareTreePosition(aFrame->GetContent(), f->GetContent(), parentViewContent) > 0) {
     800                 :       // aFrame's content is after f's content (or we just don't know),
     801                 :       // so put our view before f's view
     802               0 :       return insertBefore;
     803                 :     }
     804                 :   }
     805               0 :   return nsnull;
     806                 : }
     807                 : 
     808                 : //static
     809                 : nsIScrollableFrame*
     810               0 : nsLayoutUtils::GetScrollableFrameFor(nsIFrame *aScrolledFrame)
     811                 : {
     812               0 :   nsIFrame *frame = aScrolledFrame->GetParent();
     813               0 :   if (!frame) {
     814               0 :     return nsnull;
     815                 :   }
     816               0 :   nsIScrollableFrame *sf = do_QueryFrame(frame);
     817               0 :   return sf;
     818                 : }
     819                 : 
     820                 : nsIFrame*
     821               0 : nsLayoutUtils::GetActiveScrolledRootFor(nsIFrame* aFrame,
     822                 :                                         nsIFrame* aStopAtAncestor)
     823                 : {
     824               0 :   nsIFrame* f = aFrame;
     825               0 :   while (f != aStopAtAncestor) {
     826               0 :     if (IsPopup(f))
     827               0 :       break;
     828               0 :     nsIFrame* parent = GetCrossDocParentFrame(f);
     829               0 :     if (!parent)
     830               0 :       break;
     831               0 :     nsIScrollableFrame* sf = do_QueryFrame(parent);
     832               0 :     if (sf && sf->IsScrollingActive() && sf->GetScrolledFrame() == f)
     833               0 :       break;
     834               0 :     f = parent;
     835                 :   }
     836               0 :   return f;
     837                 : }
     838                 : 
     839                 : nsIFrame*
     840               0 : nsLayoutUtils::GetActiveScrolledRootFor(nsDisplayItem* aItem,
     841                 :                                         nsDisplayListBuilder* aBuilder,
     842                 :                                         bool* aShouldFixToViewport)
     843                 : {
     844               0 :   nsIFrame* f = aItem->GetUnderlyingFrame();
     845               0 :   if (aShouldFixToViewport) {
     846               0 :     *aShouldFixToViewport = false;
     847                 :   }
     848               0 :   if (!f) {
     849               0 :     return nsnull;
     850                 :   }
     851               0 :   if (aItem->ShouldFixToViewport(aBuilder)) {
     852               0 :     if (aShouldFixToViewport) {
     853               0 :       *aShouldFixToViewport = true;
     854                 :     }
     855                 :     // Make its active scrolled root be the active scrolled root of
     856                 :     // the enclosing viewport, since it shouldn't be scrolled by scrolled
     857                 :     // frames in its document. InvalidateFixedBackgroundFramesFromList in
     858                 :     // nsGfxScrollFrame will not repaint this item when scrolling occurs.
     859                 :     nsIFrame* viewportFrame =
     860               0 :       nsLayoutUtils::GetClosestFrameOfType(f, nsGkAtoms::viewportFrame);
     861               0 :     NS_ASSERTION(viewportFrame, "no viewport???");
     862               0 :     return nsLayoutUtils::GetActiveScrolledRootFor(viewportFrame, aBuilder->ReferenceFrame());
     863                 :   } else {
     864               0 :     return nsLayoutUtils::GetActiveScrolledRootFor(f, aBuilder->ReferenceFrame());
     865                 :   }
     866                 : }
     867                 : 
     868                 : bool
     869               0 : nsLayoutUtils::ScrolledByViewportScrolling(nsIFrame* aActiveScrolledRoot,
     870                 :                                            nsDisplayListBuilder* aBuilder)
     871                 : {
     872                 :   nsIFrame* rootScrollFrame =
     873               0 :     aBuilder->ReferenceFrame()->PresContext()->GetPresShell()->GetRootScrollFrame();
     874               0 :   return nsLayoutUtils::IsAncestorFrameCrossDoc(rootScrollFrame, aActiveScrolledRoot);
     875                 : }
     876                 : 
     877                 : // static
     878                 : nsIScrollableFrame*
     879               0 : nsLayoutUtils::GetNearestScrollableFrameForDirection(nsIFrame* aFrame,
     880                 :                                                      Direction aDirection)
     881                 : {
     882               0 :   NS_ASSERTION(aFrame, "GetNearestScrollableFrameForDirection expects a non-null frame");
     883               0 :   for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
     884               0 :     nsIScrollableFrame* scrollableFrame = do_QueryFrame(f);
     885               0 :     if (scrollableFrame) {
     886               0 :       nsPresContext::ScrollbarStyles ss = scrollableFrame->GetScrollbarStyles();
     887               0 :       PRUint32 scrollbarVisibility = scrollableFrame->GetScrollbarVisibility();
     888               0 :       nsRect scrollRange = scrollableFrame->GetScrollRange();
     889                 :       // Require visible scrollbars or something to scroll to in
     890                 :       // the given direction.
     891               0 :       if (aDirection == eVertical ?
     892                 :           (ss.mVertical != NS_STYLE_OVERFLOW_HIDDEN &&
     893                 :            ((scrollbarVisibility & nsIScrollableFrame::VERTICAL) ||
     894                 :             scrollRange.height > 0)) :
     895                 :           (ss.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN &&
     896                 :            ((scrollbarVisibility & nsIScrollableFrame::HORIZONTAL) ||
     897                 :             scrollRange.width > 0)))
     898               0 :         return scrollableFrame;
     899                 :     }
     900                 :   }
     901               0 :   return nsnull;
     902                 : }
     903                 : 
     904                 : // static
     905                 : nsIScrollableFrame*
     906               0 : nsLayoutUtils::GetNearestScrollableFrame(nsIFrame* aFrame)
     907                 : {
     908               0 :   NS_ASSERTION(aFrame, "GetNearestScrollableFrame expects a non-null frame");
     909               0 :   for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
     910               0 :     nsIScrollableFrame* scrollableFrame = do_QueryFrame(f);
     911               0 :     if (scrollableFrame) {
     912               0 :       nsPresContext::ScrollbarStyles ss = scrollableFrame->GetScrollbarStyles();
     913               0 :       if (ss.mVertical != NS_STYLE_OVERFLOW_HIDDEN ||
     914                 :           ss.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN)
     915               0 :         return scrollableFrame;
     916                 :     }
     917                 :   }
     918               0 :   return nsnull;
     919                 : }
     920                 : 
     921                 : //static
     922                 : bool
     923               0 : nsLayoutUtils::HasPseudoStyle(nsIContent* aContent,
     924                 :                               nsStyleContext* aStyleContext,
     925                 :                               nsCSSPseudoElements::Type aPseudoElement,
     926                 :                               nsPresContext* aPresContext)
     927                 : {
     928               0 :   NS_PRECONDITION(aPresContext, "Must have a prescontext");
     929                 : 
     930               0 :   nsRefPtr<nsStyleContext> pseudoContext;
     931               0 :   if (aContent) {
     932                 :     pseudoContext = aPresContext->StyleSet()->
     933                 :       ProbePseudoElementStyle(aContent->AsElement(), aPseudoElement,
     934               0 :                               aStyleContext);
     935                 :   }
     936               0 :   return pseudoContext != nsnull;
     937                 : }
     938                 : 
     939                 : nsPoint
     940               0 : nsLayoutUtils::GetDOMEventCoordinatesRelativeTo(nsIDOMEvent* aDOMEvent, nsIFrame* aFrame)
     941                 : {
     942               0 :   nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aDOMEvent));
     943               0 :   NS_ASSERTION(privateEvent, "bad implementation");
     944               0 :   if (!privateEvent)
     945               0 :     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
     946               0 :   nsEvent *event = privateEvent->GetInternalNSEvent();
     947               0 :   if (!event)
     948               0 :     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
     949               0 :   return GetEventCoordinatesRelativeTo(event, aFrame);
     950                 : }
     951                 : 
     952                 : nsPoint
     953               0 : nsLayoutUtils::GetEventCoordinatesRelativeTo(const nsEvent* aEvent, nsIFrame* aFrame)
     954                 : {
     955               0 :   if (!aEvent || (aEvent->eventStructType != NS_MOUSE_EVENT &&
     956                 :                   aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
     957                 :                   aEvent->eventStructType != NS_DRAG_EVENT &&
     958                 :                   aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT &&
     959                 :                   aEvent->eventStructType != NS_GESTURENOTIFY_EVENT &&
     960                 :                   aEvent->eventStructType != NS_MOZTOUCH_EVENT &&
     961                 : #ifdef MOZ_TOUCH
     962                 :                   aEvent->eventStructType != NS_TOUCH_EVENT &&
     963                 : #endif
     964                 :                   aEvent->eventStructType != NS_QUERY_CONTENT_EVENT))
     965               0 :     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
     966                 : 
     967               0 :   const nsGUIEvent* GUIEvent = static_cast<const nsGUIEvent*>(aEvent);
     968                 : #ifdef MOZ_TOUCH
     969                 :   return GetEventCoordinatesRelativeTo(aEvent,
     970                 :                                        GUIEvent->refPoint,
     971                 :                                        aFrame);
     972                 : #else
     973               0 :   if (!GUIEvent->widget)
     974               0 :     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
     975                 : 
     976               0 :   nsIView* view = aFrame->GetView();
     977               0 :   if (view) {
     978               0 :     nsIWidget* widget = view->GetWidget();
     979               0 :     if (widget && widget == GUIEvent->widget) {
     980                 :       // Special case this cause it happens a lot.
     981                 :       // This also fixes bug 664707, events in the extra-special case of select
     982                 :       // dropdown popups that are transformed.
     983               0 :       nsPresContext* presContext = aFrame->PresContext();
     984                 :       nsPoint pt(presContext->DevPixelsToAppUnits(GUIEvent->refPoint.x),
     985               0 :                  presContext->DevPixelsToAppUnits(GUIEvent->refPoint.y));
     986               0 :       return pt - view->ViewToWidgetOffset();
     987                 :     }
     988                 :   }
     989                 : 
     990                 :   /* If we walk up the frame tree and discover that any of the frames are
     991                 :    * transformed, we need to do extra work to convert from the global
     992                 :    * space to the local space.
     993                 :    */
     994               0 :   nsIFrame* rootFrame = aFrame;
     995               0 :   bool transformFound = false;
     996                 : 
     997               0 :   for (nsIFrame* f = aFrame; f; f = GetCrossDocParentFrame(f)) {
     998               0 :     if (f->IsTransformed())
     999               0 :       transformFound = true;
    1000               0 :     rootFrame = f;
    1001                 :   }
    1002                 : 
    1003               0 :   nsIView* rootView = rootFrame->GetView();
    1004               0 :   if (!rootView)
    1005               0 :     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    1006                 : 
    1007                 :   nsPoint widgetToView = TranslateWidgetToView(rootFrame->PresContext(),
    1008                 :                                GUIEvent->widget, GUIEvent->refPoint,
    1009               0 :                                rootView);
    1010                 : 
    1011               0 :   if (widgetToView == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE))
    1012               0 :     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    1013                 : 
    1014                 :   // Convert from root document app units to app units of the document aFrame
    1015                 :   // is in.
    1016               0 :   PRInt32 rootAPD = rootFrame->PresContext()->AppUnitsPerDevPixel();
    1017               0 :   PRInt32 localAPD = aFrame->PresContext()->AppUnitsPerDevPixel();
    1018               0 :   widgetToView = widgetToView.ConvertAppUnits(rootAPD, localAPD);
    1019                 : 
    1020                 :   /* If we encountered a transform, we can't do simple arithmetic to figure
    1021                 :    * out how to convert back to aFrame's coordinates and must use the CTM.
    1022                 :    */
    1023               0 :   if (transformFound)
    1024               0 :     return TransformRootPointToFrame(aFrame, widgetToView);
    1025                 : 
    1026                 :   /* Otherwise, all coordinate systems are translations of one another,
    1027                 :    * so we can just subtract out the different.
    1028                 :    */
    1029               0 :   return widgetToView - aFrame->GetOffsetToCrossDoc(rootFrame);
    1030                 : #endif
    1031                 : }
    1032                 : 
    1033                 : nsPoint
    1034               0 : nsLayoutUtils::GetEventCoordinatesRelativeTo(const nsEvent* aEvent,
    1035                 :                                              const nsIntPoint aPoint,
    1036                 :                                              nsIFrame* aFrame)
    1037                 : {
    1038               0 :   if (!aFrame) {
    1039               0 :     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    1040                 :   }
    1041                 : 
    1042               0 :   const nsGUIEvent* GUIEvent = static_cast<const nsGUIEvent*>(aEvent);
    1043               0 :   nsIWidget* widget = GUIEvent->widget;
    1044               0 :   if (!widget) {
    1045               0 :     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    1046                 :   }
    1047                 : 
    1048               0 :   nsIView* view = aFrame->GetView();
    1049               0 :   if (view) {
    1050               0 :     nsIWidget* frameWidget = view->GetWidget();
    1051               0 :     if (frameWidget && frameWidget == GUIEvent->widget) {
    1052                 :       // Special case this cause it happens a lot.
    1053                 :       // This also fixes bug 664707, events in the extra-special case of select
    1054                 :       // dropdown popups that are transformed.
    1055               0 :       nsPresContext* presContext = aFrame->PresContext();
    1056                 :       nsPoint pt(presContext->DevPixelsToAppUnits(aPoint.x),
    1057               0 :                  presContext->DevPixelsToAppUnits(aPoint.y));
    1058               0 :       return pt - view->ViewToWidgetOffset();
    1059                 :     }
    1060                 :   }
    1061                 : 
    1062                 :   /* If we walk up the frame tree and discover that any of the frames are
    1063                 :    * transformed, we need to do extra work to convert from the global
    1064                 :    * space to the local space.
    1065                 :    */
    1066               0 :   nsIFrame* rootFrame = aFrame;
    1067               0 :   bool transformFound = false;
    1068               0 :   for (nsIFrame* f = aFrame; f; f = GetCrossDocParentFrame(f)) {
    1069               0 :     if (f->IsTransformed()) {
    1070               0 :       transformFound = true;
    1071                 :     }
    1072                 : 
    1073               0 :     rootFrame = f;
    1074                 :   }
    1075                 : 
    1076               0 :   nsIView* rootView = rootFrame->GetView();
    1077               0 :   if (!rootView) {
    1078               0 :     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    1079                 :   }
    1080                 : 
    1081                 :   nsPoint widgetToView = TranslateWidgetToView(rootFrame->PresContext(),
    1082               0 :                                widget, aPoint, rootView);
    1083                 : 
    1084               0 :   if (widgetToView == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)) {
    1085               0 :     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    1086                 :   }
    1087                 : 
    1088                 :   // Convert from root document app units to app units of the document aFrame
    1089                 :   // is in.
    1090               0 :   PRInt32 rootAPD = rootFrame->PresContext()->AppUnitsPerDevPixel();
    1091               0 :   PRInt32 localAPD = aFrame->PresContext()->AppUnitsPerDevPixel();
    1092               0 :   widgetToView = widgetToView.ConvertAppUnits(rootAPD, localAPD);
    1093                 : 
    1094                 :   /* If we encountered a transform, we can't do simple arithmetic to figure
    1095                 :    * out how to convert back to aFrame's coordinates and must use the CTM.
    1096                 :    */
    1097               0 :   if (transformFound) {
    1098               0 :     return TransformRootPointToFrame(aFrame, widgetToView);
    1099                 :   }
    1100                 : 
    1101                 :   /* Otherwise, all coordinate systems are translations of one another,
    1102                 :    * so we can just subtract out the different.
    1103                 :    */
    1104               0 :   nsPoint offset = aFrame->GetOffsetToCrossDoc(rootFrame);
    1105               0 :   return widgetToView - offset;
    1106                 : }
    1107                 : 
    1108                 : nsIFrame*
    1109               0 : nsLayoutUtils::GetPopupFrameForEventCoordinates(nsPresContext* aPresContext,
    1110                 :                                                 const nsEvent* aEvent)
    1111                 : {
    1112                 : #ifdef MOZ_XUL
    1113               0 :   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
    1114               0 :   if (!pm) {
    1115               0 :     return nsnull;
    1116                 :   }
    1117               0 :   nsTArray<nsIFrame*> popups = pm->GetVisiblePopups();
    1118                 :   PRUint32 i;
    1119                 :   // Search from top to bottom
    1120               0 :   for (i = 0; i < popups.Length(); i++) {
    1121               0 :     nsIFrame* popup = popups[i];
    1122               0 :     if (popup->PresContext()->GetRootPresContext() == aPresContext &&
    1123               0 :         popup->GetScrollableOverflowRect().Contains(
    1124               0 :           GetEventCoordinatesRelativeTo(aEvent, popup))) {
    1125               0 :       return popup;
    1126                 :     }
    1127                 :   }
    1128                 : #endif
    1129               0 :   return nsnull;
    1130                 : }
    1131                 : 
    1132                 : gfx3DMatrix
    1133               0 : nsLayoutUtils::ChangeMatrixBasis(const gfxPoint3D &aOrigin,
    1134                 :                                  const gfx3DMatrix &aMatrix)
    1135                 : {
    1136               0 :   gfx3DMatrix result = aMatrix;
    1137                 : 
    1138                 :   /* Translate to the origin before aMatrix */
    1139               0 :   result.Translate(-aOrigin);
    1140                 : 
    1141                 :   /* Translate back into position after aMatrix */
    1142               0 :   result.TranslatePost(aOrigin);
    1143                 : 
    1144                 :   return result; 
    1145                 : }
    1146                 : 
    1147                 : /**
    1148                 :  * Given a gfxFloat, constrains its value to be between nscoord_MIN and nscoord_MAX.
    1149                 :  *
    1150                 :  * @param aVal The value to constrain (in/out)
    1151                 :  */
    1152               0 : static void ConstrainToCoordValues(gfxFloat &aVal)
    1153                 : {
    1154               0 :   if (aVal <= nscoord_MIN)
    1155               0 :     aVal = nscoord_MIN;
    1156               0 :   else if (aVal >= nscoord_MAX)
    1157               0 :     aVal = nscoord_MAX;
    1158               0 : }
    1159                 : 
    1160                 : nsRect
    1161               0 : nsLayoutUtils::RoundGfxRectToAppRect(const gfxRect &aRect, float aFactor)
    1162                 : {
    1163                 :   /* Get a new gfxRect whose units are app units by scaling by the specified factor. */
    1164               0 :   gfxRect scaledRect = aRect;
    1165               0 :   scaledRect.ScaleRoundOut(aFactor);
    1166                 : 
    1167                 :   /* We now need to constrain our results to the max and min values for coords. */
    1168               0 :   ConstrainToCoordValues(scaledRect.x);
    1169               0 :   ConstrainToCoordValues(scaledRect.y);
    1170               0 :   ConstrainToCoordValues(scaledRect.width);
    1171               0 :   ConstrainToCoordValues(scaledRect.height);
    1172                 : 
    1173                 :   /* Now typecast everything back.  This is guaranteed to be safe. */
    1174               0 :   return nsRect(nscoord(scaledRect.X()), nscoord(scaledRect.Y()),
    1175               0 :                 nscoord(scaledRect.Width()), nscoord(scaledRect.Height()));
    1176                 : }
    1177                 : 
    1178                 : 
    1179                 : nsRegion
    1180               0 : nsLayoutUtils::RoundedRectIntersectRect(const nsRect& aRoundedRect,
    1181                 :                                         const nscoord aRadii[8],
    1182                 :                                         const nsRect& aContainedRect)
    1183                 : {
    1184                 :   // rectFullHeight and rectFullWidth together will approximately contain
    1185                 :   // the total area of the frame minus the rounded corners.
    1186               0 :   nsRect rectFullHeight = aRoundedRect;
    1187               0 :   nscoord xDiff = NS_MAX(aRadii[NS_CORNER_TOP_LEFT_X], aRadii[NS_CORNER_BOTTOM_LEFT_X]);
    1188               0 :   rectFullHeight.x += xDiff;
    1189               0 :   rectFullHeight.width -= NS_MAX(aRadii[NS_CORNER_TOP_RIGHT_X],
    1190               0 :                                  aRadii[NS_CORNER_BOTTOM_RIGHT_X]) + xDiff;
    1191               0 :   nsRect r1;
    1192               0 :   r1.IntersectRect(rectFullHeight, aContainedRect);
    1193                 : 
    1194               0 :   nsRect rectFullWidth = aRoundedRect;
    1195               0 :   nscoord yDiff = NS_MAX(aRadii[NS_CORNER_TOP_LEFT_Y], aRadii[NS_CORNER_TOP_RIGHT_Y]);
    1196               0 :   rectFullWidth.y += yDiff;
    1197               0 :   rectFullWidth.height -= NS_MAX(aRadii[NS_CORNER_BOTTOM_LEFT_Y],
    1198               0 :                                  aRadii[NS_CORNER_BOTTOM_RIGHT_Y]) + yDiff;
    1199               0 :   nsRect r2;
    1200               0 :   r2.IntersectRect(rectFullWidth, aContainedRect);
    1201                 : 
    1202               0 :   nsRegion result;
    1203               0 :   result.Or(r1, r2);
    1204                 :   return result;
    1205                 : }
    1206                 : 
    1207                 : nsRect
    1208               0 : nsLayoutUtils::MatrixTransformRectOut(const nsRect &aBounds,
    1209                 :                                       const gfx3DMatrix &aMatrix, float aFactor)
    1210                 : {
    1211               0 :   nsRect outside = aBounds;
    1212               0 :   outside.ScaleRoundOut(1/aFactor);
    1213                 :   gfxRect image = aMatrix.TransformBounds(gfxRect(outside.x,
    1214                 :                                                   outside.y,
    1215                 :                                                   outside.width,
    1216               0 :                                                   outside.height));
    1217               0 :   return RoundGfxRectToAppRect(image, aFactor);
    1218                 : }
    1219                 : 
    1220                 : nsRect
    1221               0 : nsLayoutUtils::MatrixTransformRect(const nsRect &aBounds,
    1222                 :                                    const gfx3DMatrix &aMatrix, float aFactor)
    1223                 : {
    1224                 :   gfxRect image = aMatrix.TransformBounds(gfxRect(NSAppUnitsToDoublePixels(aBounds.x, aFactor),
    1225                 :                                                   NSAppUnitsToDoublePixels(aBounds.y, aFactor),
    1226                 :                                                   NSAppUnitsToDoublePixels(aBounds.width, aFactor),
    1227               0 :                                                   NSAppUnitsToDoublePixels(aBounds.height, aFactor)));
    1228                 : 
    1229               0 :   return RoundGfxRectToAppRect(image, aFactor);
    1230                 : }
    1231                 : 
    1232                 : nsPoint
    1233               0 : nsLayoutUtils::MatrixTransformPoint(const nsPoint &aPoint,
    1234                 :                                     const gfx3DMatrix &aMatrix, float aFactor)
    1235                 : {
    1236               0 :   gfxPoint image = aMatrix.Transform(gfxPoint(NSAppUnitsToFloatPixels(aPoint.x, aFactor),
    1237               0 :                                               NSAppUnitsToFloatPixels(aPoint.y, aFactor)));
    1238                 :   return nsPoint(NSFloatPixelsToAppUnits(float(image.x), aFactor),
    1239               0 :                  NSFloatPixelsToAppUnits(float(image.y), aFactor));
    1240                 : }
    1241                 : 
    1242                 : gfx3DMatrix
    1243               0 : nsLayoutUtils::GetTransformToAncestor(nsIFrame *aFrame, nsIFrame *aAncestor)
    1244                 : {
    1245                 :   nsIFrame* parent;
    1246               0 :   gfx3DMatrix ctm = aFrame->GetTransformMatrix(aAncestor, &parent);
    1247               0 :   while (parent && parent != aAncestor) {
    1248               0 :     if (!parent->Preserves3DChildren()) {
    1249               0 :       ctm.ProjectTo2D();
    1250                 :     }
    1251               0 :     ctm = ctm * parent->GetTransformMatrix(aAncestor, &parent);
    1252                 :   }
    1253                 :   return ctm;
    1254                 : }
    1255                 : 
    1256                 : static gfxPoint
    1257               0 : TransformGfxPointFromAncestor(nsIFrame *aFrame,
    1258                 :                               const gfxPoint &aPoint,
    1259                 :                               nsIFrame *aAncestor)
    1260                 : {
    1261               0 :   gfx3DMatrix ctm = nsLayoutUtils::GetTransformToAncestor(aFrame, aAncestor);
    1262               0 :   return ctm.Inverse().ProjectPoint(aPoint);
    1263                 : }
    1264                 : 
    1265                 : static gfxRect
    1266               0 : TransformGfxRectFromAncestor(nsIFrame *aFrame,
    1267                 :                              const gfxRect &aRect,
    1268                 :                              nsIFrame *aAncestor)
    1269                 : {
    1270               0 :   gfx3DMatrix ctm = nsLayoutUtils::GetTransformToAncestor(aFrame, aAncestor);
    1271               0 :   return ctm.Inverse().ProjectRectBounds(aRect);
    1272                 : }
    1273                 : 
    1274                 : static gfxRect
    1275               0 : TransformGfxRectToAncestor(nsIFrame *aFrame,
    1276                 :                            const gfxRect &aRect,
    1277                 :                            nsIFrame *aAncestor)
    1278                 : {
    1279               0 :   gfx3DMatrix ctm = nsLayoutUtils::GetTransformToAncestor(aFrame, aAncestor);
    1280               0 :   return ctm.TransformBounds(aRect);
    1281                 : }
    1282                 : 
    1283                 : nsPoint
    1284               0 : nsLayoutUtils::TransformRootPointToFrame(nsIFrame *aFrame,
    1285                 :                                          const nsPoint &aPoint)
    1286                 : {
    1287               0 :     float factor = aFrame->PresContext()->AppUnitsPerDevPixel();
    1288               0 :     gfxPoint result(NSAppUnitsToFloatPixels(aPoint.x, factor),
    1289               0 :                     NSAppUnitsToFloatPixels(aPoint.y, factor));
    1290                 :     
    1291               0 :     result = TransformGfxPointFromAncestor(aFrame, result, nsnull);
    1292                 :    
    1293                 :     return nsPoint(NSFloatPixelsToAppUnits(float(result.x), factor),
    1294               0 :                    NSFloatPixelsToAppUnits(float(result.y), factor));
    1295                 : }
    1296                 : 
    1297                 : nsRect 
    1298               0 : nsLayoutUtils::TransformAncestorRectToFrame(nsIFrame* aFrame,
    1299                 :                                             const nsRect &aRect,
    1300                 :                                             nsIFrame* aAncestor)
    1301                 : {
    1302               0 :     float factor = aFrame->PresContext()->AppUnitsPerDevPixel();
    1303               0 :     gfxRect result(NSAppUnitsToFloatPixels(aRect.x, factor),
    1304               0 :                    NSAppUnitsToFloatPixels(aRect.y, factor),
    1305               0 :                    NSAppUnitsToFloatPixels(aRect.width, factor),
    1306               0 :                    NSAppUnitsToFloatPixels(aRect.height, factor));
    1307                 : 
    1308               0 :     result = TransformGfxRectFromAncestor(aFrame, result, aAncestor);
    1309                 : 
    1310                 :     return nsRect(NSFloatPixelsToAppUnits(float(result.x), factor),
    1311                 :                   NSFloatPixelsToAppUnits(float(result.y), factor),
    1312                 :                   NSFloatPixelsToAppUnits(float(result.width), factor),
    1313               0 :                   NSFloatPixelsToAppUnits(float(result.height), factor));
    1314                 : }
    1315                 : 
    1316                 : nsRect
    1317               0 : nsLayoutUtils::TransformFrameRectToAncestor(nsIFrame* aFrame,
    1318                 :                                             const nsRect& aRect,
    1319                 :                                             nsIFrame* aAncestor)
    1320                 : {
    1321               0 :   float factor = aFrame->PresContext()->AppUnitsPerDevPixel();
    1322               0 :   gfxRect result(NSAppUnitsToFloatPixels(aRect.x, factor),
    1323               0 :                  NSAppUnitsToFloatPixels(aRect.y, factor),
    1324               0 :                  NSAppUnitsToFloatPixels(aRect.width, factor),
    1325               0 :                  NSAppUnitsToFloatPixels(aRect.height, factor));
    1326                 : 
    1327               0 :   result = TransformGfxRectToAncestor(aFrame, result, aAncestor);
    1328                 : 
    1329                 :   return nsRect(NSFloatPixelsToAppUnits(float(result.x), factor),
    1330                 :                 NSFloatPixelsToAppUnits(float(result.y), factor),
    1331                 :                 NSFloatPixelsToAppUnits(float(result.width), factor),
    1332               0 :                 NSFloatPixelsToAppUnits(float(result.height), factor));
    1333                 : }
    1334                 : 
    1335               0 : static nsIntPoint GetWidgetOffset(nsIWidget* aWidget, nsIWidget*& aRootWidget) {
    1336               0 :   nsIntPoint offset(0, 0);
    1337               0 :   nsIWidget* parent = aWidget->GetParent();
    1338               0 :   while (parent) {
    1339               0 :     nsIntRect bounds;
    1340               0 :     aWidget->GetBounds(bounds);
    1341               0 :     offset += bounds.TopLeft();
    1342               0 :     aWidget = parent;
    1343               0 :     parent = aWidget->GetParent();
    1344                 :   }
    1345               0 :   aRootWidget = aWidget;
    1346                 :   return offset;
    1347                 : }
    1348                 : 
    1349                 : nsPoint
    1350               0 : nsLayoutUtils::TranslateWidgetToView(nsPresContext* aPresContext,
    1351                 :                                      nsIWidget* aWidget, nsIntPoint aPt,
    1352                 :                                      nsIView* aView)
    1353                 : {
    1354               0 :   nsPoint viewOffset;
    1355               0 :   nsIWidget* viewWidget = aView->GetNearestWidget(&viewOffset);
    1356               0 :   if (!viewWidget) {
    1357               0 :     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    1358                 :   }
    1359                 : 
    1360                 :   nsIWidget* fromRoot;
    1361               0 :   nsIntPoint fromOffset = GetWidgetOffset(aWidget, fromRoot);
    1362                 :   nsIWidget* toRoot;
    1363               0 :   nsIntPoint toOffset = GetWidgetOffset(viewWidget, toRoot);
    1364                 : 
    1365               0 :   nsIntPoint widgetPoint;
    1366               0 :   if (fromRoot == toRoot) {
    1367               0 :     widgetPoint = aPt + fromOffset - toOffset;
    1368                 :   } else {
    1369               0 :     nsIntPoint screenPoint = aWidget->WidgetToScreenOffset();
    1370               0 :     widgetPoint = aPt + screenPoint - viewWidget->WidgetToScreenOffset();
    1371                 :   }
    1372                 : 
    1373                 :   nsPoint widgetAppUnits(aPresContext->DevPixelsToAppUnits(widgetPoint.x),
    1374               0 :                          aPresContext->DevPixelsToAppUnits(widgetPoint.y));
    1375               0 :   return widgetAppUnits - viewOffset;
    1376                 : }
    1377                 : 
    1378                 : // Combine aNewBreakType with aOrigBreakType, but limit the break types
    1379                 : // to NS_STYLE_CLEAR_LEFT, RIGHT, LEFT_AND_RIGHT.
    1380                 : PRUint8
    1381               0 : nsLayoutUtils::CombineBreakType(PRUint8 aOrigBreakType,
    1382                 :                                 PRUint8 aNewBreakType)
    1383                 : {
    1384               0 :   PRUint8 breakType = aOrigBreakType;
    1385               0 :   switch(breakType) {
    1386                 :   case NS_STYLE_CLEAR_LEFT:
    1387               0 :     if ((NS_STYLE_CLEAR_RIGHT          == aNewBreakType) ||
    1388                 :         (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aNewBreakType)) {
    1389               0 :       breakType = NS_STYLE_CLEAR_LEFT_AND_RIGHT;
    1390                 :     }
    1391               0 :     break;
    1392                 :   case NS_STYLE_CLEAR_RIGHT:
    1393               0 :     if ((NS_STYLE_CLEAR_LEFT           == aNewBreakType) ||
    1394                 :         (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aNewBreakType)) {
    1395               0 :       breakType = NS_STYLE_CLEAR_LEFT_AND_RIGHT;
    1396                 :     }
    1397               0 :     break;
    1398                 :   case NS_STYLE_CLEAR_NONE:
    1399               0 :     if ((NS_STYLE_CLEAR_LEFT           == aNewBreakType) ||
    1400                 :         (NS_STYLE_CLEAR_RIGHT          == aNewBreakType) ||
    1401                 :         (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aNewBreakType)) {
    1402               0 :       breakType = aNewBreakType;
    1403                 :     }
    1404                 :   }
    1405               0 :   return breakType;
    1406                 : }
    1407                 : 
    1408                 : #ifdef MOZ_DUMP_PAINTING
    1409                 : #include <stdio.h>
    1410                 : 
    1411                 : static bool gDumpEventList = false;
    1412                 : int gPaintCount = 0;
    1413                 : #endif
    1414                 : 
    1415                 : nsresult
    1416               0 : nsLayoutUtils::GetRemoteContentIds(nsIFrame* aFrame,
    1417                 :                                    const nsRect& aTarget,
    1418                 :                                    nsTArray<ViewID> &aOutIDs,
    1419                 :                                    bool aIgnoreRootScrollFrame)
    1420                 : {
    1421                 :   nsDisplayListBuilder builder(aFrame, nsDisplayListBuilder::EVENT_DELIVERY,
    1422               0 :                                false);
    1423               0 :   nsDisplayList list;
    1424                 : 
    1425               0 :   if (aIgnoreRootScrollFrame) {
    1426                 :     nsIFrame* rootScrollFrame =
    1427               0 :       aFrame->PresContext()->PresShell()->GetRootScrollFrame();
    1428               0 :     if (rootScrollFrame) {
    1429               0 :       builder.SetIgnoreScrollFrame(rootScrollFrame);
    1430                 :     }
    1431                 :   }
    1432                 : 
    1433               0 :   builder.EnterPresShell(aFrame, aTarget);
    1434                 : 
    1435                 :   nsresult rv =
    1436               0 :     aFrame->BuildDisplayListForStackingContext(&builder, aTarget, &list);
    1437                 : 
    1438               0 :   builder.LeavePresShell(aFrame, aTarget);
    1439               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1440                 : 
    1441               0 :   nsAutoTArray<nsIFrame*,8> outFrames;
    1442               0 :   nsDisplayItem::HitTestState hitTestState(&aOutIDs);
    1443               0 :   list.HitTest(&builder, aTarget, &hitTestState, &outFrames);
    1444               0 :   list.DeleteAll();
    1445                 : 
    1446               0 :   return NS_OK;
    1447                 : }
    1448                 : 
    1449                 : nsIFrame*
    1450               0 : nsLayoutUtils::GetFrameForPoint(nsIFrame* aFrame, nsPoint aPt,
    1451                 :                                 bool aShouldIgnoreSuppression,
    1452                 :                                 bool aIgnoreRootScrollFrame)
    1453                 : {
    1454                 :   nsresult rv;
    1455               0 :   nsAutoTArray<nsIFrame*,8> outFrames;
    1456               0 :   rv = GetFramesForArea(aFrame, nsRect(aPt, nsSize(1, 1)), outFrames,
    1457               0 :                         aShouldIgnoreSuppression, aIgnoreRootScrollFrame);
    1458               0 :   NS_ENSURE_SUCCESS(rv, nsnull);
    1459               0 :   return outFrames.Length() ? outFrames.ElementAt(0) : nsnull;
    1460                 : }
    1461                 : 
    1462                 : nsresult
    1463               0 : nsLayoutUtils::GetFramesForArea(nsIFrame* aFrame, const nsRect& aRect,
    1464                 :                                 nsTArray<nsIFrame*> &aOutFrames,
    1465                 :                                 bool aShouldIgnoreSuppression,
    1466                 :                                 bool aIgnoreRootScrollFrame)
    1467                 : {
    1468                 :   nsDisplayListBuilder builder(aFrame, nsDisplayListBuilder::EVENT_DELIVERY,
    1469               0 :                                        false);
    1470               0 :   nsDisplayList list;
    1471               0 :   nsRect target(aRect);
    1472                 : 
    1473               0 :   if (aShouldIgnoreSuppression) {
    1474               0 :     builder.IgnorePaintSuppression();
    1475                 :   }
    1476                 : 
    1477               0 :   if (aIgnoreRootScrollFrame) {
    1478                 :     nsIFrame* rootScrollFrame =
    1479               0 :       aFrame->PresContext()->PresShell()->GetRootScrollFrame();
    1480               0 :     if (rootScrollFrame) {
    1481               0 :       builder.SetIgnoreScrollFrame(rootScrollFrame);
    1482                 :     }
    1483                 :   }
    1484                 : 
    1485               0 :   builder.EnterPresShell(aFrame, target);
    1486                 : 
    1487                 :   nsresult rv =
    1488               0 :     aFrame->BuildDisplayListForStackingContext(&builder, target, &list);
    1489                 : 
    1490               0 :   builder.LeavePresShell(aFrame, target);
    1491               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1492                 : 
    1493                 : #ifdef MOZ_DUMP_PAINTING
    1494               0 :   if (gDumpEventList) {
    1495               0 :     fprintf(stdout, "Event handling --- (%d,%d):\n", aRect.x, aRect.y);
    1496               0 :     nsFrame::PrintDisplayList(&builder, list);
    1497                 :   }
    1498                 : #endif
    1499                 : 
    1500               0 :   nsDisplayItem::HitTestState hitTestState;
    1501               0 :   list.HitTest(&builder, target, &hitTestState, &aOutFrames);
    1502               0 :   list.DeleteAll();
    1503               0 :   return NS_OK;
    1504                 : }
    1505                 : 
    1506                 : /**
    1507                 :  * Remove all leaf display items that are not for descendants of
    1508                 :  * aBuilder->GetReferenceFrame() from aList, and move all nsDisplayClip
    1509                 :  * wrappers to their correct locations.
    1510                 :  * @param aExtraPage the page we constructed aList for
    1511                 :  * @param aY the Y-coordinate where aPage would be positioned relative
    1512                 :  * to the main page (aBuilder->GetReferenceFrame()), considering only
    1513                 :  * the content and ignoring page margins and dead space
    1514                 :  * @param aList the list that is modified in-place
    1515                 :  */
    1516                 : static void
    1517               0 : PruneDisplayListForExtraPage(nsDisplayListBuilder* aBuilder,
    1518                 :         nsIFrame* aExtraPage, nscoord aY, nsDisplayList* aList)
    1519                 : {
    1520               0 :   nsDisplayList newList;
    1521                 :   // The page which we're really constructing a display list for
    1522               0 :   nsIFrame* mainPage = aBuilder->ReferenceFrame();
    1523                 : 
    1524               0 :   while (true) {
    1525               0 :     nsDisplayItem* i = aList->RemoveBottom();
    1526               0 :     if (!i)
    1527                 :       break;
    1528               0 :     nsDisplayList* subList = i->GetList();
    1529               0 :     if (subList) {
    1530               0 :       PruneDisplayListForExtraPage(aBuilder, aExtraPage, aY, subList);
    1531               0 :       nsDisplayItem::Type type = i->GetType();
    1532               0 :       if (type == nsDisplayItem::TYPE_CLIP ||
    1533                 :           type == nsDisplayItem::TYPE_CLIP_ROUNDED_RECT) {
    1534                 :         // This might clip an element which should appear on the first
    1535                 :         // page, and that element might be visible if this uses a 'clip'
    1536                 :         // property with a negative top.
    1537                 :         // The clip area needs to be moved because the frame geometry doesn't
    1538                 :         // put page content frames for adjacent pages vertically adjacent,
    1539                 :         // there are page margins and dead space between them in print
    1540                 :         // preview, and in printing all pages are at (0,0)...
    1541                 :         // XXX we have no way to test this right now that I know of;
    1542                 :         // the 'clip' property requires an abs-pos element and we never
    1543                 :         // paint abs-pos elements that start after the main page
    1544                 :         // (bug 426909).
    1545               0 :         nsDisplayClip* clip = static_cast<nsDisplayClip*>(i);
    1546               0 :         clip->SetClipRect(clip->GetClipRect() + nsPoint(0, aY) -
    1547               0 :                 aExtraPage->GetOffsetTo(mainPage));
    1548                 :       }
    1549               0 :       newList.AppendToTop(i);
    1550                 :     } else {
    1551               0 :       nsIFrame* f = i->GetUnderlyingFrame();
    1552               0 :       if (f && nsLayoutUtils::IsProperAncestorFrameCrossDoc(mainPage, f)) {
    1553                 :         // This one is in the page we care about, keep it
    1554               0 :         newList.AppendToTop(i);
    1555                 :       } else {
    1556                 :         // We're throwing this away so call its destructor now. The memory
    1557                 :         // is owned by aBuilder which destroys all items at once.
    1558               0 :         i->~nsDisplayItem();
    1559                 :       }
    1560                 :     }
    1561                 :   }
    1562               0 :   aList->AppendToTop(&newList);
    1563               0 : }
    1564                 : 
    1565                 : static nsresult
    1566               0 : BuildDisplayListForExtraPage(nsDisplayListBuilder* aBuilder,
    1567                 :         nsIFrame* aPage, nscoord aY, nsDisplayList* aList)
    1568                 : {
    1569               0 :   nsDisplayList list;
    1570                 :   // Pass an empty dirty rect since we're only interested in finding
    1571                 :   // placeholders whose out-of-flows are in the page
    1572                 :   // aBuilder->GetReferenceFrame(), and the paths to those placeholders
    1573                 :   // have already been marked as NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO.
    1574                 :   // Note that we should still do a prune step since we don't want to
    1575                 :   // rely on dirty-rect checking for correctness.
    1576               0 :   nsresult rv = aPage->BuildDisplayListForStackingContext(aBuilder, nsRect(), &list);
    1577               0 :   if (NS_FAILED(rv))
    1578               0 :     return rv;
    1579               0 :   PruneDisplayListForExtraPage(aBuilder, aPage, aY, &list);
    1580               0 :   aList->AppendToTop(&list);
    1581               0 :   return NS_OK;
    1582                 : }
    1583                 : 
    1584                 : static nsIFrame*
    1585               0 : GetNextPage(nsIFrame* aPageContentFrame)
    1586                 : {
    1587                 :   // XXX ugh
    1588               0 :   nsIFrame* pageFrame = aPageContentFrame->GetParent();
    1589               0 :   NS_ASSERTION(pageFrame->GetType() == nsGkAtoms::pageFrame,
    1590                 :                "pageContentFrame has unexpected parent");
    1591               0 :   nsIFrame* nextPageFrame = pageFrame->GetNextSibling();
    1592               0 :   if (!nextPageFrame)
    1593               0 :     return nsnull;
    1594               0 :   NS_ASSERTION(nextPageFrame->GetType() == nsGkAtoms::pageFrame,
    1595                 :                "pageFrame's sibling is not a page frame...");
    1596               0 :   nsIFrame* f = nextPageFrame->GetFirstPrincipalChild();
    1597               0 :   NS_ASSERTION(f, "pageFrame has no page content frame!");
    1598               0 :   NS_ASSERTION(f->GetType() == nsGkAtoms::pageContentFrame,
    1599                 :                "pageFrame's child is not page content!");
    1600               0 :   return f;
    1601                 : }
    1602                 : 
    1603                 : nsresult
    1604               0 : nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFrame,
    1605                 :                           const nsRegion& aDirtyRegion, nscolor aBackstop,
    1606                 :                           PRUint32 aFlags)
    1607                 : {
    1608               0 :   if (aFlags & PAINT_WIDGET_LAYERS) {
    1609               0 :     nsIView* view = aFrame->GetView();
    1610               0 :     if (!(view && view->GetWidget() && GetDisplayRootFrame(aFrame) == aFrame)) {
    1611               0 :       aFlags &= ~PAINT_WIDGET_LAYERS;
    1612               0 :       NS_ASSERTION(aRenderingContext, "need a rendering context");
    1613                 :     }
    1614                 :   }
    1615                 : 
    1616               0 :   nsPresContext* presContext = aFrame->PresContext();
    1617               0 :   nsIPresShell* presShell = presContext->PresShell();
    1618                 : 
    1619               0 :   nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
    1620               0 :   bool usingDisplayPort = false;
    1621               0 :   nsRect displayport;
    1622               0 :   if (rootScrollFrame) {
    1623               0 :     nsIContent* content = rootScrollFrame->GetContent();
    1624               0 :     if (content) {
    1625               0 :       usingDisplayPort = nsLayoutUtils::GetDisplayPort(content, &displayport);
    1626                 :     }
    1627                 :   }
    1628                 : 
    1629               0 :   bool ignoreViewportScrolling = presShell->IgnoringViewportScrolling();
    1630               0 :   nsRegion visibleRegion;
    1631               0 :   if (aFlags & PAINT_WIDGET_LAYERS) {
    1632                 :     // This layer tree will be reused, so we'll need to calculate it
    1633                 :     // for the whole "visible" area of the window
    1634                 :     // 
    1635                 :     // |ignoreViewportScrolling| and |usingDisplayPort| are persistent
    1636                 :     // document-rendering state.  We rely on PresShell to flush
    1637                 :     // retained layers as needed when that persistent state changes.
    1638               0 :     if (!usingDisplayPort) {
    1639               0 :       visibleRegion = aFrame->GetVisualOverflowRectRelativeToSelf();
    1640                 :     } else {
    1641               0 :       visibleRegion = displayport;
    1642                 :     }
    1643                 :   } else {
    1644               0 :     visibleRegion = aDirtyRegion;
    1645                 :   }
    1646                 : 
    1647                 :   // If we're going to display something different from what we'd normally
    1648                 :   // paint in a window then we will flush out any retained layer trees before
    1649                 :   // *and after* we draw.
    1650               0 :   bool willFlushRetainedLayers = (aFlags & PAINT_HIDE_CARET) != 0;
    1651                 : 
    1652                 :   nsDisplayListBuilder builder(aFrame, nsDisplayListBuilder::PAINTING,
    1653               0 :                                        !(aFlags & PAINT_HIDE_CARET));
    1654               0 :   if (usingDisplayPort) {
    1655               0 :     builder.SetDisplayPort(displayport);
    1656                 :   }
    1657                 : 
    1658               0 :   nsDisplayList list;
    1659               0 :   if (aFlags & PAINT_IN_TRANSFORM) {
    1660               0 :     builder.SetInTransform(true);
    1661                 :   }
    1662               0 :   if (aFlags & PAINT_SYNC_DECODE_IMAGES) {
    1663               0 :     builder.SetSyncDecodeImages(true);
    1664                 :   }
    1665               0 :   if (aFlags & (PAINT_WIDGET_LAYERS | PAINT_TO_WINDOW)) {
    1666               0 :     builder.SetPaintingToWindow(true);
    1667                 :   }
    1668               0 :   if (aFlags & PAINT_IGNORE_SUPPRESSION) {
    1669               0 :     builder.IgnorePaintSuppression();
    1670                 :   }
    1671               0 :   if (aRenderingContext &&
    1672               0 :       aRenderingContext->ThebesContext()->GetFlags() & gfxContext::FLAG_DISABLE_SNAPPING) {
    1673               0 :     builder.SetSnappingEnabled(false);
    1674                 :   }
    1675               0 :   nsRect canvasArea(nsPoint(0, 0), aFrame->GetSize());
    1676                 : 
    1677                 : #ifdef DEBUG
    1678               0 :   if (ignoreViewportScrolling) {
    1679               0 :     nsIDocument* doc = aFrame->GetContent() ?
    1680               0 :       aFrame->GetContent()->GetCurrentDoc() : nsnull;
    1681               0 :     NS_ASSERTION(!aFrame->GetParent() ||
    1682                 :                  (doc && doc->IsBeingUsedAsImage()),
    1683                 :                  "Only expecting ignoreViewportScrolling for root frames and "
    1684                 :                  "for image documents.");
    1685                 :   }
    1686                 : #endif
    1687                 : 
    1688               0 :   if (ignoreViewportScrolling && !aFrame->GetParent()) {
    1689               0 :     nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
    1690               0 :     if (rootScrollFrame) {
    1691                 :       nsIScrollableFrame* rootScrollableFrame =
    1692               0 :         presShell->GetRootScrollFrameAsScrollable();
    1693               0 :       if (aFlags & PAINT_DOCUMENT_RELATIVE) {
    1694                 :         // Make visibleRegion and aRenderingContext relative to the
    1695                 :         // scrolled frame instead of the root frame.
    1696               0 :         nsPoint pos = rootScrollableFrame->GetScrollPosition();
    1697               0 :         visibleRegion.MoveBy(-pos);
    1698               0 :         if (aRenderingContext) {
    1699               0 :           aRenderingContext->Translate(pos);
    1700                 :         }
    1701                 :       }
    1702               0 :       builder.SetIgnoreScrollFrame(rootScrollFrame);
    1703                 : 
    1704                 :       nsCanvasFrame* canvasFrame =
    1705               0 :         do_QueryFrame(rootScrollableFrame->GetScrolledFrame());
    1706               0 :       if (canvasFrame) {
    1707                 :         // Use UnionRect here to ensure that areas where the scrollbars
    1708                 :         // were are still filled with the background color.
    1709                 :         canvasArea.UnionRect(canvasArea,
    1710               0 :           canvasFrame->CanvasArea() + builder.ToReferenceFrame(canvasFrame));
    1711                 :       }
    1712                 :     }
    1713                 :   }
    1714                 :   nsresult rv;
    1715                 : 
    1716               0 :   nsRect dirtyRect = visibleRegion.GetBounds();
    1717               0 :   builder.EnterPresShell(aFrame, dirtyRect);
    1718                 : 
    1719               0 :   rv = aFrame->BuildDisplayListForStackingContext(&builder, dirtyRect, &list);
    1720                 : 
    1721               0 :   const bool paintAllContinuations = aFlags & PAINT_ALL_CONTINUATIONS;
    1722               0 :   NS_ASSERTION(!paintAllContinuations || !aFrame->GetPrevContinuation(),
    1723                 :                "If painting all continuations, the frame must be "
    1724                 :                "first-continuation");
    1725                 : 
    1726               0 :   nsIAtom* frameType = aFrame->GetType();
    1727               0 :   if (NS_SUCCEEDED(rv) && !paintAllContinuations &&
    1728                 :       frameType == nsGkAtoms::pageContentFrame) {
    1729               0 :     NS_ASSERTION(!(aFlags & PAINT_WIDGET_LAYERS),
    1730                 :       "shouldn't be painting with widget layers for page content frames");
    1731                 :     // We may need to paint out-of-flow frames whose placeholders are
    1732                 :     // on other pages. Add those pages to our display list. Note that
    1733                 :     // out-of-flow frames can't be placed after their placeholders so
    1734                 :     // we don't have to process earlier pages. The display lists for
    1735                 :     // these extra pages are pruned so that only display items for the
    1736                 :     // page we currently care about (which we would have reached by
    1737                 :     // following placeholders to their out-of-flows) end up on the list.
    1738               0 :     nsIFrame* page = aFrame;
    1739               0 :     nscoord y = aFrame->GetSize().height;
    1740               0 :     while ((page = GetNextPage(page)) != nsnull) {
    1741               0 :       rv = BuildDisplayListForExtraPage(&builder, page, y, &list);
    1742               0 :       if (NS_FAILED(rv))
    1743               0 :         break;
    1744               0 :       y += page->GetSize().height;
    1745                 :     }
    1746                 :   }
    1747                 : 
    1748               0 :   if (paintAllContinuations) {
    1749               0 :     nsIFrame* currentFrame = aFrame;
    1750               0 :     while (NS_SUCCEEDED(rv) &&
    1751               0 :            (currentFrame = currentFrame->GetNextContinuation()) != nsnull) {
    1752               0 :       nsRect frameDirty = dirtyRect - builder.ToReferenceFrame(currentFrame);
    1753                 :       rv = currentFrame->BuildDisplayListForStackingContext(&builder,
    1754               0 :                                                             frameDirty, &list);
    1755                 :     }
    1756                 :   }
    1757                 : 
    1758                 :   // For the viewport frame in print preview/page layout we want to paint
    1759                 :   // the grey background behind the page, not the canvas color.
    1760               0 :   if (frameType == nsGkAtoms::viewportFrame && 
    1761               0 :       nsLayoutUtils::NeedsPrintPreviewBackground(presContext)) {
    1762                 :     nsRect bounds = nsRect(builder.ToReferenceFrame(aFrame),
    1763               0 :                            aFrame->GetSize());
    1764               0 :     rv = presShell->AddPrintPreviewBackgroundItem(builder, list, aFrame, bounds);
    1765               0 :   } else if (frameType != nsGkAtoms::pageFrame) {
    1766                 :     // For printing, this function is first called on an nsPageFrame, which
    1767                 :     // creates a display list with a PageContent item. The PageContent item's
    1768                 :     // paint function calls this function on the nsPageFrame's child which is
    1769                 :     // an nsPageContentFrame. We only want to add the canvas background color
    1770                 :     // item once, for the nsPageContentFrame.
    1771                 : 
    1772                 :     // Add the canvas background color to the bottom of the list. This
    1773                 :     // happens after we've built the list so that AddCanvasBackgroundColorItem
    1774                 :     // can monkey with the contents if necessary.
    1775               0 :     canvasArea.IntersectRect(canvasArea, visibleRegion.GetBounds());
    1776                 :     rv = presShell->AddCanvasBackgroundColorItem(
    1777               0 :            builder, list, aFrame, canvasArea, aBackstop);
    1778                 : 
    1779                 :     // If the passed in backstop color makes us draw something different from
    1780                 :     // normal, we need to flush layers.
    1781               0 :     if ((aFlags & PAINT_WIDGET_LAYERS) && !willFlushRetainedLayers) {
    1782               0 :       nsIView* view = aFrame->GetView();
    1783               0 :       if (view) {
    1784               0 :         nscolor backstop = presShell->ComputeBackstopColor(view);
    1785                 :         // The PresShell's canvas background color doesn't get updated until
    1786                 :         // EnterPresShell, so this check has to be done after that.
    1787               0 :         nscolor canvasColor = presShell->GetCanvasBackground();
    1788               0 :         if (NS_ComposeColors(aBackstop, canvasColor) !=
    1789               0 :             NS_ComposeColors(backstop, canvasColor)) {
    1790               0 :           willFlushRetainedLayers = true;
    1791                 :         }
    1792                 :       }
    1793                 :     }
    1794                 :   }
    1795                 : 
    1796               0 :   builder.LeavePresShell(aFrame, dirtyRect);
    1797               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1798                 : 
    1799               0 :   if (builder.GetHadToIgnorePaintSuppression()) {
    1800               0 :     willFlushRetainedLayers = true;
    1801                 :   }
    1802                 : 
    1803                 : #ifdef MOZ_DUMP_PAINTING
    1804               0 :   if (gfxUtils::sDumpPainting) {
    1805               0 :     if (gfxUtils::sDumpPaintingToFile) {
    1806               0 :       nsCString string("dump-");
    1807               0 :       string.AppendInt(gPaintCount);
    1808               0 :       string.Append(".html");
    1809               0 :       gfxUtils::sDumpPaintFile = fopen(string.BeginReading(), "w");
    1810                 :     } else {
    1811               0 :       gfxUtils::sDumpPaintFile = stdout;
    1812                 :     }
    1813               0 :     fprintf(gfxUtils::sDumpPaintFile, "<html><head><script>var array = {}; function ViewImage(index) { window.location = array[index]; }</script></head><body>");
    1814                 :     fprintf(gfxUtils::sDumpPaintFile, "Painting --- before optimization (dirty %d,%d,%d,%d):\n",
    1815               0 :             dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
    1816               0 :     nsFrame::PrintDisplayList(&builder, list, gfxUtils::sDumpPaintFile);
    1817               0 :     if (gfxUtils::sDumpPaintingToFile) {
    1818               0 :       fprintf(gfxUtils::sDumpPaintFile, "<script>");
    1819                 :     }
    1820                 :   }
    1821                 : #endif
    1822                 : 
    1823               0 :   list.ComputeVisibilityForRoot(&builder, &visibleRegion);
    1824                 : 
    1825               0 :   PRUint32 flags = nsDisplayList::PAINT_DEFAULT;
    1826               0 :   if (aFlags & PAINT_WIDGET_LAYERS) {
    1827               0 :     flags |= nsDisplayList::PAINT_USE_WIDGET_LAYERS;
    1828               0 :     if (willFlushRetainedLayers) {
    1829                 :       // The caller wanted to paint from retained layers, but set up
    1830                 :       // the paint in such a way that we can't use them.  We're going
    1831                 :       // to display something different from what we'd normally paint
    1832                 :       // in a window, so make sure we flush out any retained layer
    1833                 :       // trees before *and after* we draw.  Callers should be fixed to
    1834                 :       // not do this.
    1835               0 :       NS_WARNING("Flushing retained layers!");
    1836               0 :       flags |= nsDisplayList::PAINT_FLUSH_LAYERS;
    1837               0 :     } else if (!(aFlags & PAINT_DOCUMENT_RELATIVE)) {
    1838               0 :       nsIWidget *widget = aFrame->GetNearestWidget();
    1839               0 :       if (widget) {
    1840               0 :         builder.SetFinalTransparentRegion(visibleRegion);
    1841                 :         // If we're finished building display list items for painting of the outermost
    1842                 :         // pres shell, notify the widget about any toolbars we've encountered.
    1843               0 :         widget->UpdateThemeGeometries(builder.GetThemeGeometries());
    1844                 :       }
    1845                 :     }
    1846                 :   }
    1847               0 :   if (aFlags & PAINT_EXISTING_TRANSACTION) {
    1848               0 :     flags |= nsDisplayList::PAINT_EXISTING_TRANSACTION;
    1849                 :   }
    1850                 : 
    1851               0 :   list.PaintRoot(&builder, aRenderingContext, flags);
    1852                 : 
    1853                 :   // Update the widget's opaque region information. This sets
    1854                 :   // glass boundaries on Windows.
    1855               0 :   if ((aFlags & PAINT_WIDGET_LAYERS) &&
    1856               0 :       !willFlushRetainedLayers &&
    1857               0 :       !(aFlags & PAINT_DOCUMENT_RELATIVE)) {
    1858               0 :     nsIWidget *widget = aFrame->GetNearestWidget();
    1859               0 :     if (widget) {
    1860               0 :       nsRegion excludedRegion = builder.GetExcludedGlassRegion();
    1861               0 :       excludedRegion.Sub(excludedRegion, visibleRegion);
    1862               0 :       nsIntRegion windowRegion(excludedRegion.ToNearestPixels(presContext->AppUnitsPerDevPixel()));
    1863               0 :       widget->UpdateOpaqueRegion(windowRegion);
    1864                 :     }
    1865                 :   }
    1866                 : 
    1867                 : #ifdef MOZ_DUMP_PAINTING
    1868               0 :   if (gfxUtils::sDumpPainting) {
    1869               0 :     fprintf(gfxUtils::sDumpPaintFile, "</script>Painting --- after optimization:\n");
    1870               0 :     nsFrame::PrintDisplayList(&builder, list, gfxUtils::sDumpPaintFile);
    1871                 : 
    1872               0 :     fprintf(gfxUtils::sDumpPaintFile, "Painting --- retained layer tree:\n");
    1873               0 :     builder.LayerBuilder()->DumpRetainedLayerTree(gfxUtils::sDumpPaintFile);
    1874               0 :     fprintf(gfxUtils::sDumpPaintFile, "</body></html>");
    1875                 :     
    1876               0 :     if (gfxUtils::sDumpPaintingToFile) {
    1877               0 :       fclose(gfxUtils::sDumpPaintFile);
    1878                 :     }
    1879               0 :     gfxUtils::sDumpPaintFile = NULL;
    1880               0 :     gPaintCount++;
    1881                 :   }
    1882                 : #endif
    1883                 : 
    1884                 :   // Flush the list so we don't trigger the IsEmpty-on-destruction assertion
    1885               0 :   list.DeleteAll();
    1886               0 :   return NS_OK;
    1887                 : }
    1888                 : 
    1889                 : PRInt32
    1890               0 : nsLayoutUtils::GetZIndex(nsIFrame* aFrame) {
    1891               0 :   if (!aFrame->GetStyleDisplay()->IsPositioned())
    1892               0 :     return 0;
    1893                 : 
    1894                 :   const nsStylePosition* position =
    1895               0 :     aFrame->GetStylePosition();
    1896               0 :   if (position->mZIndex.GetUnit() == eStyleUnit_Integer)
    1897               0 :     return position->mZIndex.GetIntValue();
    1898                 : 
    1899                 :   // sort the auto and 0 elements together
    1900               0 :   return 0;
    1901                 : }
    1902                 : 
    1903                 : /**
    1904                 :  * Uses a binary search for find where the cursor falls in the line of text
    1905                 :  * It also keeps track of the part of the string that has already been measured
    1906                 :  * so it doesn't have to keep measuring the same text over and over
    1907                 :  *
    1908                 :  * @param "aBaseWidth" contains the width in twips of the portion
    1909                 :  * of the text that has already been measured, and aBaseInx contains
    1910                 :  * the index of the text that has already been measured.
    1911                 :  *
    1912                 :  * @param aTextWidth returns the (in twips) the length of the text that falls
    1913                 :  * before the cursor aIndex contains the index of the text where the cursor falls
    1914                 :  */
    1915                 : bool
    1916               0 : nsLayoutUtils::BinarySearchForPosition(nsRenderingContext* aRendContext,
    1917                 :                         const PRUnichar* aText,
    1918                 :                         PRInt32    aBaseWidth,
    1919                 :                         PRInt32    aBaseInx,
    1920                 :                         PRInt32    aStartInx,
    1921                 :                         PRInt32    aEndInx,
    1922                 :                         PRInt32    aCursorPos,
    1923                 :                         PRInt32&   aIndex,
    1924                 :                         PRInt32&   aTextWidth)
    1925                 : {
    1926               0 :   PRInt32 range = aEndInx - aStartInx;
    1927               0 :   if ((range == 1) || (range == 2 && NS_IS_HIGH_SURROGATE(aText[aStartInx]))) {
    1928               0 :     aIndex   = aStartInx + aBaseInx;
    1929               0 :     aTextWidth = aRendContext->GetWidth(aText, aIndex);
    1930               0 :     return true;
    1931                 :   }
    1932                 : 
    1933               0 :   PRInt32 inx = aStartInx + (range / 2);
    1934                 : 
    1935                 :   // Make sure we don't leave a dangling low surrogate
    1936               0 :   if (NS_IS_HIGH_SURROGATE(aText[inx-1]))
    1937               0 :     inx++;
    1938                 : 
    1939               0 :   PRInt32 textWidth = aRendContext->GetWidth(aText, inx);
    1940                 : 
    1941               0 :   PRInt32 fullWidth = aBaseWidth + textWidth;
    1942               0 :   if (fullWidth == aCursorPos) {
    1943               0 :     aTextWidth = textWidth;
    1944               0 :     aIndex = inx;
    1945               0 :     return true;
    1946               0 :   } else if (aCursorPos < fullWidth) {
    1947               0 :     aTextWidth = aBaseWidth;
    1948               0 :     if (BinarySearchForPosition(aRendContext, aText, aBaseWidth, aBaseInx, aStartInx, inx, aCursorPos, aIndex, aTextWidth)) {
    1949               0 :       return true;
    1950                 :     }
    1951                 :   } else {
    1952               0 :     aTextWidth = fullWidth;
    1953               0 :     if (BinarySearchForPosition(aRendContext, aText, aBaseWidth, aBaseInx, inx, aEndInx, aCursorPos, aIndex, aTextWidth)) {
    1954               0 :       return true;
    1955                 :     }
    1956                 :   }
    1957               0 :   return false;
    1958                 : }
    1959                 : 
    1960                 : static void
    1961               0 : AddBoxesForFrame(nsIFrame* aFrame,
    1962                 :                  nsLayoutUtils::BoxCallback* aCallback)
    1963                 : {
    1964               0 :   nsIAtom* pseudoType = aFrame->GetStyleContext()->GetPseudo();
    1965                 : 
    1966               0 :   if (pseudoType == nsCSSAnonBoxes::tableOuter) {
    1967               0 :     AddBoxesForFrame(aFrame->GetFirstPrincipalChild(), aCallback);
    1968               0 :     nsIFrame* kid = aFrame->GetFirstChild(nsIFrame::kCaptionList);
    1969               0 :     if (kid) {
    1970               0 :       AddBoxesForFrame(kid, aCallback);
    1971                 :     }
    1972               0 :   } else if (pseudoType == nsCSSAnonBoxes::mozAnonymousBlock ||
    1973                 :              pseudoType == nsCSSAnonBoxes::mozAnonymousPositionedBlock ||
    1974                 :              pseudoType == nsCSSAnonBoxes::mozMathMLAnonymousBlock ||
    1975                 :              pseudoType == nsCSSAnonBoxes::mozXULAnonymousBlock) {
    1976               0 :     for (nsIFrame* kid = aFrame->GetFirstPrincipalChild(); kid; kid = kid->GetNextSibling()) {
    1977               0 :       AddBoxesForFrame(kid, aCallback);
    1978               0 :     }
    1979                 :   } else {
    1980               0 :     aCallback->AddBox(aFrame);
    1981                 :   }
    1982               0 : }
    1983                 : 
    1984                 : void
    1985               0 : nsLayoutUtils::GetAllInFlowBoxes(nsIFrame* aFrame, BoxCallback* aCallback)
    1986                 : {
    1987               0 :   while (aFrame) {
    1988               0 :     AddBoxesForFrame(aFrame, aCallback);
    1989               0 :     aFrame = nsLayoutUtils::GetNextContinuationOrSpecialSibling(aFrame);
    1990                 :   }
    1991               0 : }
    1992                 : 
    1993                 : struct BoxToBorderRect : public nsLayoutUtils::BoxCallback {
    1994                 :   nsIFrame* mRelativeTo;
    1995                 :   nsLayoutUtils::RectCallback* mCallback;
    1996                 :   PRUint32 mFlags;
    1997                 : 
    1998               0 :   BoxToBorderRect(nsIFrame* aRelativeTo, nsLayoutUtils::RectCallback* aCallback,
    1999                 :                   PRUint32 aFlags)
    2000               0 :     : mRelativeTo(aRelativeTo), mCallback(aCallback), mFlags(aFlags) {}
    2001                 : 
    2002               0 :   virtual void AddBox(nsIFrame* aFrame) {
    2003               0 :     nsRect r;
    2004               0 :     nsIFrame* outer = nsSVGUtils::GetOuterSVGFrameAndCoveredRegion(aFrame, &r);
    2005               0 :     if (!outer) {
    2006               0 :       outer = aFrame;
    2007               0 :       r = nsRect(nsPoint(0, 0), aFrame->GetSize());
    2008                 :     }
    2009               0 :     if (mFlags & nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS) {
    2010               0 :       r = nsLayoutUtils::TransformFrameRectToAncestor(outer, r, mRelativeTo);
    2011                 :     } else {
    2012               0 :       r += outer->GetOffsetTo(mRelativeTo);
    2013                 :     }
    2014               0 :     mCallback->AddRect(r);
    2015               0 :   }
    2016                 : };
    2017                 : 
    2018                 : void
    2019               0 : nsLayoutUtils::GetAllInFlowRects(nsIFrame* aFrame, nsIFrame* aRelativeTo,
    2020                 :                                  RectCallback* aCallback, PRUint32 aFlags)
    2021                 : {
    2022               0 :   BoxToBorderRect converter(aRelativeTo, aCallback, aFlags);
    2023               0 :   GetAllInFlowBoxes(aFrame, &converter);
    2024               0 : }
    2025                 : 
    2026               0 : nsLayoutUtils::RectAccumulator::RectAccumulator() : mSeenFirstRect(false) {}
    2027                 : 
    2028               0 : void nsLayoutUtils::RectAccumulator::AddRect(const nsRect& aRect) {
    2029               0 :   mResultRect.UnionRect(mResultRect, aRect);
    2030               0 :   if (!mSeenFirstRect) {
    2031               0 :     mSeenFirstRect = true;
    2032               0 :     mFirstRect = aRect;
    2033                 :   }
    2034               0 : }
    2035                 : 
    2036               0 : nsLayoutUtils::RectListBuilder::RectListBuilder(nsClientRectList* aList)
    2037               0 :   : mRectList(aList), mRV(NS_OK) {}
    2038                 : 
    2039               0 : void nsLayoutUtils::RectListBuilder::AddRect(const nsRect& aRect) {
    2040               0 :   nsRefPtr<nsClientRect> rect = new nsClientRect();
    2041                 : 
    2042               0 :   rect->SetLayoutRect(aRect);
    2043               0 :   mRectList->Append(rect);
    2044               0 : }
    2045                 : 
    2046               0 : nsIFrame* nsLayoutUtils::GetContainingBlockForClientRect(nsIFrame* aFrame)
    2047                 : {
    2048               0 :   return aFrame->PresContext()->PresShell()->GetRootFrame();
    2049                 : }
    2050                 : 
    2051                 : nsRect
    2052               0 : nsLayoutUtils::GetAllInFlowRectsUnion(nsIFrame* aFrame, nsIFrame* aRelativeTo,
    2053                 :                                       PRUint32 aFlags) {
    2054               0 :   RectAccumulator accumulator;
    2055               0 :   GetAllInFlowRects(aFrame, aRelativeTo, &accumulator, aFlags);
    2056               0 :   return accumulator.mResultRect.IsEmpty() ? accumulator.mFirstRect
    2057               0 :           : accumulator.mResultRect;
    2058                 : }
    2059                 : 
    2060                 : nsRect
    2061               0 : nsLayoutUtils::GetTextShadowRectsUnion(const nsRect& aTextAndDecorationsRect,
    2062                 :                                        nsIFrame* aFrame,
    2063                 :                                        PRUint32 aFlags)
    2064                 : {
    2065               0 :   const nsStyleText* textStyle = aFrame->GetStyleText();
    2066               0 :   if (!textStyle->mTextShadow)
    2067               0 :     return aTextAndDecorationsRect;
    2068                 : 
    2069               0 :   nsRect resultRect = aTextAndDecorationsRect;
    2070               0 :   PRInt32 A2D = aFrame->PresContext()->AppUnitsPerDevPixel();
    2071               0 :   for (PRUint32 i = 0; i < textStyle->mTextShadow->Length(); ++i) {
    2072               0 :     nsCSSShadowItem* shadow = textStyle->mTextShadow->ShadowAt(i);
    2073               0 :     nsMargin blur = nsContextBoxBlur::GetBlurRadiusMargin(shadow->mRadius, A2D);
    2074               0 :     if ((aFlags & EXCLUDE_BLUR_SHADOWS) && blur != nsMargin(0, 0, 0, 0))
    2075               0 :       continue;
    2076                 : 
    2077               0 :     nsRect tmpRect(aTextAndDecorationsRect);
    2078                 : 
    2079               0 :     tmpRect.MoveBy(nsPoint(shadow->mXOffset, shadow->mYOffset));
    2080               0 :     tmpRect.Inflate(blur);
    2081                 : 
    2082               0 :     resultRect.UnionRect(resultRect, tmpRect);
    2083                 :   }
    2084               0 :   return resultRect;
    2085                 : }
    2086                 : 
    2087                 : nsresult
    2088               0 : nsLayoutUtils::GetFontMetricsForFrame(const nsIFrame* aFrame,
    2089                 :                                       nsFontMetrics** aFontMetrics,
    2090                 :                                       float aInflation)
    2091                 : {
    2092                 :   return nsLayoutUtils::GetFontMetricsForStyleContext(aFrame->GetStyleContext(),
    2093                 :                                                       aFontMetrics,
    2094               0 :                                                       aInflation);
    2095                 : }
    2096                 : 
    2097                 : nsresult
    2098               0 : nsLayoutUtils::GetFontMetricsForStyleContext(nsStyleContext* aStyleContext,
    2099                 :                                              nsFontMetrics** aFontMetrics,
    2100                 :                                              float aInflation)
    2101                 : {
    2102                 :   // pass the user font set object into the device context to pass along to CreateFontGroup
    2103               0 :   gfxUserFontSet* fs = aStyleContext->PresContext()->GetUserFontSet();
    2104                 : 
    2105               0 :   nsFont font = aStyleContext->GetStyleFont()->mFont;
    2106                 :   // We need to not run font.size through floats when it's large since
    2107                 :   // doing so would be lossy.  Fortunately, in such cases, aInflation is
    2108                 :   // guaranteed to be 1.0f.
    2109               0 :   if (aInflation != 1.0f) {
    2110               0 :     font.size = NSToCoordRound(font.size * aInflation);
    2111                 :   }
    2112                 :   return aStyleContext->PresContext()->DeviceContext()->GetMetricsFor(
    2113               0 :                   font, aStyleContext->GetStyleFont()->mLanguage,
    2114               0 :                   fs, *aFontMetrics);
    2115                 : }
    2116                 : 
    2117                 : nsIFrame*
    2118               0 : nsLayoutUtils::FindChildContainingDescendant(nsIFrame* aParent, nsIFrame* aDescendantFrame)
    2119                 : {
    2120               0 :   nsIFrame* result = aDescendantFrame;
    2121                 : 
    2122               0 :   while (result) {
    2123               0 :     nsIFrame* parent = result->GetParent();
    2124               0 :     if (parent == aParent) {
    2125               0 :       break;
    2126                 :     }
    2127                 : 
    2128                 :     // The frame is not an immediate child of aParent so walk up another level
    2129               0 :     result = parent;
    2130                 :   }
    2131                 : 
    2132               0 :   return result;
    2133                 : }
    2134                 : 
    2135                 : nsBlockFrame*
    2136               0 : nsLayoutUtils::GetAsBlock(nsIFrame* aFrame)
    2137                 : {
    2138               0 :   nsBlockFrame* block = do_QueryFrame(aFrame);
    2139               0 :   return block;
    2140                 : }
    2141                 : 
    2142                 : nsBlockFrame*
    2143               0 : nsLayoutUtils::FindNearestBlockAncestor(nsIFrame* aFrame)
    2144                 : {
    2145                 :   nsIFrame* nextAncestor;
    2146               0 :   for (nextAncestor = aFrame->GetParent(); nextAncestor;
    2147                 :        nextAncestor = nextAncestor->GetParent()) {
    2148               0 :     nsBlockFrame* block = GetAsBlock(nextAncestor);
    2149               0 :     if (block)
    2150               0 :       return block;
    2151                 :   }
    2152               0 :   return nsnull;
    2153                 : }
    2154                 : 
    2155                 : nsIFrame*
    2156               0 : nsLayoutUtils::GetNonGeneratedAncestor(nsIFrame* aFrame)
    2157                 : {
    2158               0 :   if (!(aFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT))
    2159               0 :     return aFrame;
    2160                 : 
    2161               0 :   nsFrameManager* frameManager = aFrame->PresContext()->FrameManager();
    2162               0 :   nsIFrame* f = aFrame;
    2163               0 :   do {
    2164               0 :     f = GetParentOrPlaceholderFor(frameManager, f);
    2165               0 :   } while (f->GetStateBits() & NS_FRAME_GENERATED_CONTENT);
    2166               0 :   return f;
    2167                 : }
    2168                 : 
    2169                 : nsIFrame*
    2170               0 : nsLayoutUtils::GetParentOrPlaceholderFor(nsFrameManager* aFrameManager,
    2171                 :                                          nsIFrame* aFrame)
    2172                 : {
    2173               0 :   if ((aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
    2174               0 :       && !aFrame->GetPrevInFlow()) {
    2175               0 :     return aFrameManager->GetPlaceholderFrameFor(aFrame);
    2176                 :   }
    2177               0 :   return aFrame->GetParent();
    2178                 : }
    2179                 : 
    2180                 : nsIFrame*
    2181               0 : nsLayoutUtils::GetNextContinuationOrSpecialSibling(nsIFrame *aFrame)
    2182                 : {
    2183               0 :   nsIFrame *result = aFrame->GetNextContinuation();
    2184               0 :   if (result)
    2185               0 :     return result;
    2186                 : 
    2187               0 :   if ((aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL) != 0) {
    2188                 :     // We only store the "special sibling" annotation with the first
    2189                 :     // frame in the continuation chain. Walk back to find that frame now.
    2190               0 :     aFrame = aFrame->GetFirstContinuation();
    2191                 : 
    2192               0 :     void* value = aFrame->Properties().Get(nsIFrame::IBSplitSpecialSibling());
    2193               0 :     return static_cast<nsIFrame*>(value);
    2194                 :   }
    2195                 : 
    2196               0 :   return nsnull;
    2197                 : }
    2198                 : 
    2199                 : nsIFrame*
    2200               0 : nsLayoutUtils::GetFirstContinuationOrSpecialSibling(nsIFrame *aFrame)
    2201                 : {
    2202               0 :   nsIFrame *result = aFrame->GetFirstContinuation();
    2203               0 :   if (result->GetStateBits() & NS_FRAME_IS_SPECIAL) {
    2204               0 :     while (true) {
    2205                 :       nsIFrame *f = static_cast<nsIFrame*>
    2206               0 :         (result->Properties().Get(nsIFrame::IBSplitSpecialPrevSibling()));
    2207               0 :       if (!f)
    2208                 :         break;
    2209               0 :       result = f;
    2210                 :     }
    2211                 :   }
    2212                 : 
    2213               0 :   return result;
    2214                 : }
    2215                 : 
    2216                 : bool
    2217               0 : nsLayoutUtils::IsViewportScrollbarFrame(nsIFrame* aFrame)
    2218                 : {
    2219               0 :   if (!aFrame)
    2220               0 :     return false;
    2221                 : 
    2222                 :   nsIFrame* rootScrollFrame =
    2223               0 :     aFrame->PresContext()->PresShell()->GetRootScrollFrame();
    2224               0 :   if (!rootScrollFrame)
    2225               0 :     return false;
    2226                 : 
    2227               0 :   nsIScrollableFrame* rootScrollableFrame = do_QueryFrame(rootScrollFrame);
    2228               0 :   NS_ASSERTION(rootScrollableFrame, "The root scorollable frame is null");
    2229                 : 
    2230               0 :   if (!IsProperAncestorFrame(rootScrollFrame, aFrame))
    2231               0 :     return false;
    2232                 : 
    2233               0 :   nsIFrame* rootScrolledFrame = rootScrollableFrame->GetScrolledFrame();
    2234                 :   return !(rootScrolledFrame == aFrame ||
    2235               0 :            IsProperAncestorFrame(rootScrolledFrame, aFrame));
    2236                 : }
    2237                 : 
    2238               0 : static nscoord AddPercents(nsLayoutUtils::IntrinsicWidthType aType,
    2239                 :                            nscoord aCurrent, float aPercent)
    2240                 : {
    2241               0 :   nscoord result = aCurrent;
    2242               0 :   if (aPercent > 0.0f && aType == nsLayoutUtils::PREF_WIDTH) {
    2243                 :     // XXX Should we also consider percentages for min widths, up to a
    2244                 :     // limit?
    2245               0 :     if (aPercent >= 1.0f)
    2246               0 :       result = nscoord_MAX;
    2247                 :     else
    2248               0 :       result = NSToCoordRound(float(result) / (1.0f - aPercent));
    2249                 :   }
    2250               0 :   return result;
    2251                 : }
    2252                 : 
    2253                 : // Use only for widths/heights (or their min/max), since it clamps
    2254                 : // negative calc() results to 0.
    2255               0 : static bool GetAbsoluteCoord(const nsStyleCoord& aStyle, nscoord& aResult)
    2256                 : {
    2257               0 :   if (aStyle.IsCalcUnit()) {
    2258               0 :     if (aStyle.CalcHasPercent()) {
    2259               0 :       return false;
    2260                 :     }
    2261                 :     // If it has no percents, we can pass 0 for the percentage basis.
    2262               0 :     aResult = nsRuleNode::ComputeComputedCalc(aStyle, 0);
    2263               0 :     if (aResult < 0)
    2264               0 :       aResult = 0;
    2265               0 :     return true;
    2266                 :   }
    2267                 : 
    2268               0 :   if (eStyleUnit_Coord != aStyle.GetUnit())
    2269               0 :     return false;
    2270                 : 
    2271               0 :   aResult = aStyle.GetCoordValue();
    2272               0 :   NS_ASSERTION(aResult >= 0, "negative widths not allowed");
    2273               0 :   return true;
    2274                 : }
    2275                 : 
    2276                 : static bool
    2277               0 : GetPercentHeight(const nsStyleCoord& aStyle,
    2278                 :                  nsIFrame* aFrame,
    2279                 :                  nscoord& aResult)
    2280                 : {
    2281               0 :   if (eStyleUnit_Percent != aStyle.GetUnit())
    2282               0 :     return false;
    2283                 : 
    2284               0 :   nsIFrame *f = aFrame->GetContainingBlock();
    2285               0 :   if (!f) {
    2286               0 :     NS_NOTREACHED("top of frame tree not a containing block");
    2287               0 :     return false;
    2288                 :   }
    2289                 : 
    2290               0 :   const nsStylePosition *pos = f->GetStylePosition();
    2291                 :   nscoord h;
    2292               0 :   if (!GetAbsoluteCoord(pos->mHeight, h) &&
    2293               0 :       !GetPercentHeight(pos->mHeight, f, h)) {
    2294               0 :     NS_ASSERTION(pos->mHeight.GetUnit() == eStyleUnit_Auto ||
    2295                 :                  pos->mHeight.HasPercent(),
    2296                 :                  "unknown height unit");
    2297               0 :     nsIAtom* fType = f->GetType();
    2298               0 :     if (fType != nsGkAtoms::viewportFrame && fType != nsGkAtoms::canvasFrame &&
    2299                 :         fType != nsGkAtoms::pageContentFrame) {
    2300                 :       // There's no basis for the percentage height, so it acts like auto.
    2301                 :       // Should we consider a max-height < min-height pair a basis for
    2302                 :       // percentage heights?  The spec is somewhat unclear, and not doing
    2303                 :       // so is simpler and avoids troubling discontinuities in behavior,
    2304                 :       // so I'll choose not to. -LDB
    2305               0 :       return false;
    2306                 :     }
    2307                 : 
    2308               0 :     NS_ASSERTION(pos->mHeight.GetUnit() == eStyleUnit_Auto,
    2309                 :                  "Unexpected height unit for viewport or canvas or page-content");
    2310                 :     // For the viewport, canvas, and page-content kids, the percentage
    2311                 :     // basis is just the parent height.
    2312               0 :     h = f->GetSize().height;
    2313               0 :     if (h == NS_UNCONSTRAINEDSIZE) {
    2314                 :       // We don't have a percentage basis after all
    2315               0 :       return false;
    2316                 :     }
    2317                 :   }
    2318                 : 
    2319                 :   nscoord maxh;
    2320               0 :   if (GetAbsoluteCoord(pos->mMaxHeight, maxh) ||
    2321               0 :       GetPercentHeight(pos->mMaxHeight, f, maxh)) {
    2322               0 :     if (maxh < h)
    2323               0 :       h = maxh;
    2324                 :   } else {
    2325               0 :     NS_ASSERTION(pos->mMaxHeight.GetUnit() == eStyleUnit_None ||
    2326                 :                  pos->mMaxHeight.HasPercent(),
    2327                 :                  "unknown max-height unit");
    2328                 :   }
    2329                 : 
    2330                 :   nscoord minh;
    2331               0 :   if (GetAbsoluteCoord(pos->mMinHeight, minh) ||
    2332               0 :       GetPercentHeight(pos->mMinHeight, f, minh)) {
    2333               0 :     if (minh > h)
    2334               0 :       h = minh;
    2335                 :   } else {
    2336               0 :     NS_ASSERTION(pos->mMinHeight.HasPercent(),
    2337                 :                  "unknown min-height unit");
    2338                 :   }
    2339                 : 
    2340               0 :   aResult = NSToCoordRound(aStyle.GetPercentValue() * h);
    2341               0 :   return true;
    2342                 : }
    2343                 : 
    2344                 : // Handles only -moz-max-content and -moz-min-content, and
    2345                 : // -moz-fit-content for min-width and max-width, since the others
    2346                 : // (-moz-fit-content for width, and -moz-available) have no effect on
    2347                 : // intrinsic widths.
    2348                 : enum eWidthProperty { PROP_WIDTH, PROP_MAX_WIDTH, PROP_MIN_WIDTH };
    2349                 : static bool
    2350               0 : GetIntrinsicCoord(const nsStyleCoord& aStyle,
    2351                 :                   nsRenderingContext* aRenderingContext,
    2352                 :                   nsIFrame* aFrame,
    2353                 :                   eWidthProperty aProperty,
    2354                 :                   nscoord& aResult)
    2355                 : {
    2356               0 :   NS_PRECONDITION(aProperty == PROP_WIDTH || aProperty == PROP_MAX_WIDTH ||
    2357                 :                   aProperty == PROP_MIN_WIDTH, "unexpected property");
    2358               0 :   if (aStyle.GetUnit() != eStyleUnit_Enumerated)
    2359               0 :     return false;
    2360               0 :   PRInt32 val = aStyle.GetIntValue();
    2361               0 :   NS_ASSERTION(val == NS_STYLE_WIDTH_MAX_CONTENT ||
    2362                 :                val == NS_STYLE_WIDTH_MIN_CONTENT ||
    2363                 :                val == NS_STYLE_WIDTH_FIT_CONTENT ||
    2364                 :                val == NS_STYLE_WIDTH_AVAILABLE,
    2365                 :                "unexpected enumerated value for width property");
    2366               0 :   if (val == NS_STYLE_WIDTH_AVAILABLE)
    2367               0 :     return false;
    2368               0 :   if (val == NS_STYLE_WIDTH_FIT_CONTENT) {
    2369               0 :     if (aProperty == PROP_WIDTH)
    2370               0 :       return false; // handle like 'width: auto'
    2371               0 :     if (aProperty == PROP_MAX_WIDTH)
    2372                 :       // constrain large 'width' values down to -moz-max-content
    2373               0 :       val = NS_STYLE_WIDTH_MAX_CONTENT;
    2374                 :     else
    2375                 :       // constrain small 'width' or 'max-width' values up to -moz-min-content
    2376               0 :       val = NS_STYLE_WIDTH_MIN_CONTENT;
    2377                 :   }
    2378                 : 
    2379               0 :   NS_ASSERTION(val == NS_STYLE_WIDTH_MAX_CONTENT ||
    2380                 :                val == NS_STYLE_WIDTH_MIN_CONTENT,
    2381                 :                "should have reduced everything remaining to one of these");
    2382                 : 
    2383                 :   // If aFrame is a container for font size inflation, then shrink
    2384                 :   // wrapping inside of it should not apply font size inflation.
    2385               0 :   AutoMaybeNullInflationContainer an(aFrame);
    2386                 : 
    2387               0 :   if (val == NS_STYLE_WIDTH_MAX_CONTENT)
    2388               0 :     aResult = aFrame->GetPrefWidth(aRenderingContext);
    2389                 :   else
    2390               0 :     aResult = aFrame->GetMinWidth(aRenderingContext);
    2391               0 :   return true;
    2392                 : }
    2393                 : 
    2394                 : #undef  DEBUG_INTRINSIC_WIDTH
    2395                 : 
    2396                 : #ifdef DEBUG_INTRINSIC_WIDTH
    2397                 : static PRInt32 gNoiseIndent = 0;
    2398                 : #endif
    2399                 : 
    2400                 : /* static */ nscoord
    2401               0 : nsLayoutUtils::IntrinsicForContainer(nsRenderingContext *aRenderingContext,
    2402                 :                                      nsIFrame *aFrame,
    2403                 :                                      IntrinsicWidthType aType)
    2404                 : {
    2405               0 :   NS_PRECONDITION(aFrame, "null frame");
    2406               0 :   NS_PRECONDITION(aType == MIN_WIDTH || aType == PREF_WIDTH, "bad type");
    2407                 : 
    2408                 : #ifdef DEBUG_INTRINSIC_WIDTH
    2409                 :   nsFrame::IndentBy(stdout, gNoiseIndent);
    2410                 :   static_cast<nsFrame*>(aFrame)->ListTag(stdout);
    2411                 :   printf(" %s intrinsic width for container:\n",
    2412                 :          aType == MIN_WIDTH ? "min" : "pref");
    2413                 : #endif
    2414                 : 
    2415                 :   // If aFrame is a container for font size inflation, then shrink
    2416                 :   // wrapping inside of it should not apply font size inflation.
    2417               0 :   AutoMaybeNullInflationContainer an(aFrame);
    2418                 : 
    2419                 :   nsIFrame::IntrinsicWidthOffsetData offsets =
    2420               0 :     aFrame->IntrinsicWidthOffsets(aRenderingContext);
    2421                 : 
    2422               0 :   const nsStylePosition *stylePos = aFrame->GetStylePosition();
    2423               0 :   PRUint8 boxSizing = stylePos->mBoxSizing;
    2424               0 :   const nsStyleCoord &styleWidth = stylePos->mWidth;
    2425               0 :   const nsStyleCoord &styleMinWidth = stylePos->mMinWidth;
    2426               0 :   const nsStyleCoord &styleMaxWidth = stylePos->mMaxWidth;
    2427                 : 
    2428                 :   // We build up two values starting with the content box, and then
    2429                 :   // adding padding, border and margin.  The result is normally
    2430                 :   // |result|.  Then, when we handle 'width', 'min-width', and
    2431                 :   // 'max-width', we use the results we've been building in |min| as a
    2432                 :   // minimum, overriding 'min-width'.  This ensures two things:
    2433                 :   //   * that we don't let a value of 'box-sizing' specifying a width
    2434                 :   //     smaller than the padding/border inside the box-sizing box give
    2435                 :   //     a content width less than zero
    2436                 :   //   * that we prevent tables from becoming smaller than their
    2437                 :   //     intrinsic minimum width
    2438               0 :   nscoord result = 0, min = 0;
    2439                 : 
    2440                 :   nscoord maxw;
    2441               0 :   bool haveFixedMaxWidth = GetAbsoluteCoord(styleMaxWidth, maxw);
    2442                 :   nscoord minw;
    2443               0 :   bool haveFixedMinWidth = GetAbsoluteCoord(styleMinWidth, minw);
    2444                 : 
    2445                 :   // If we have a specified width (or a specified 'min-width' greater
    2446                 :   // than the specified 'max-width', which works out to the same thing),
    2447                 :   // don't even bother getting the frame's intrinsic width.
    2448               0 :   if (styleWidth.GetUnit() == eStyleUnit_Enumerated &&
    2449               0 :       (styleWidth.GetIntValue() == NS_STYLE_WIDTH_MAX_CONTENT ||
    2450               0 :        styleWidth.GetIntValue() == NS_STYLE_WIDTH_MIN_CONTENT)) {
    2451                 :     // -moz-fit-content and -moz-available enumerated widths compute intrinsic
    2452                 :     // widths just like auto.
    2453                 :     // For -moz-max-content and -moz-min-content, we handle them like
    2454                 :     // specified widths, but ignore -moz-box-sizing.
    2455               0 :     boxSizing = NS_STYLE_BOX_SIZING_CONTENT;
    2456               0 :   } else if (styleWidth.GetUnit() != eStyleUnit_Coord &&
    2457               0 :              !(haveFixedMinWidth && haveFixedMaxWidth && maxw <= minw)) {
    2458                 : #ifdef DEBUG_INTRINSIC_WIDTH
    2459                 :     ++gNoiseIndent;
    2460                 : #endif
    2461               0 :     if (aType == MIN_WIDTH)
    2462               0 :       result = aFrame->GetMinWidth(aRenderingContext);
    2463                 :     else
    2464               0 :       result = aFrame->GetPrefWidth(aRenderingContext);
    2465                 : #ifdef DEBUG_INTRINSIC_WIDTH
    2466                 :     --gNoiseIndent;
    2467                 :     nsFrame::IndentBy(stdout, gNoiseIndent);
    2468                 :     static_cast<nsFrame*>(aFrame)->ListTag(stdout);
    2469                 :     printf(" %s intrinsic width from frame is %d.\n",
    2470                 :            aType == MIN_WIDTH ? "min" : "pref", result);
    2471                 : #endif
    2472                 : 
    2473                 :     // Handle elements with an intrinsic ratio (or size) and a specified
    2474                 :     // height, min-height, or max-height.
    2475               0 :     const nsStyleCoord &styleHeight = stylePos->mHeight;
    2476               0 :     const nsStyleCoord &styleMinHeight = stylePos->mMinHeight;
    2477               0 :     const nsStyleCoord &styleMaxHeight = stylePos->mMaxHeight;
    2478               0 :     if (styleHeight.GetUnit() != eStyleUnit_Auto ||
    2479               0 :         !(styleMinHeight.GetUnit() == eStyleUnit_Coord &&
    2480               0 :           styleMinHeight.GetCoordValue() == 0) ||
    2481               0 :         styleMaxHeight.GetUnit() != eStyleUnit_None) {
    2482                 : 
    2483               0 :       nsSize ratio = aFrame->GetIntrinsicRatio();
    2484                 : 
    2485               0 :       if (ratio.height != 0) {
    2486                 : 
    2487                 :         nscoord h;
    2488               0 :         if (GetAbsoluteCoord(styleHeight, h) ||
    2489               0 :             GetPercentHeight(styleHeight, aFrame, h)) {
    2490                 :           result =
    2491               0 :             NSToCoordRound(h * (float(ratio.width) / float(ratio.height)));
    2492                 :         }
    2493                 : 
    2494               0 :         if (GetAbsoluteCoord(styleMaxHeight, h) ||
    2495               0 :             GetPercentHeight(styleMaxHeight, aFrame, h)) {
    2496               0 :           h = NSToCoordRound(h * (float(ratio.width) / float(ratio.height)));
    2497               0 :           if (h < result)
    2498               0 :             result = h;
    2499                 :         }
    2500                 : 
    2501               0 :         if (GetAbsoluteCoord(styleMinHeight, h) ||
    2502               0 :             GetPercentHeight(styleMinHeight, aFrame, h)) {
    2503               0 :           h = NSToCoordRound(h * (float(ratio.width) / float(ratio.height)));
    2504               0 :           if (h > result)
    2505               0 :             result = h;
    2506                 :         }
    2507                 :       }
    2508                 :     }
    2509                 :   }
    2510                 : 
    2511               0 :   if (aFrame->GetType() == nsGkAtoms::tableFrame) {
    2512                 :     // Tables can't shrink smaller than their intrinsic minimum width,
    2513                 :     // no matter what.
    2514               0 :     min = aFrame->GetMinWidth(aRenderingContext);
    2515                 :   }
    2516                 : 
    2517                 :   // We also need to track what has been added on outside of the box
    2518                 :   // (controlled by 'box-sizing') where 'width', 'min-width' and
    2519                 :   // 'max-width' are applied.  We have to account for these properties
    2520                 :   // after getting all the offsets (margin, border, padding) because
    2521                 :   // percentages do not operate linearly.
    2522                 :   // Doing this is ok because although percentages aren't handled
    2523                 :   // linearly, they are handled monotonically.
    2524               0 :   nscoord coordOutsideWidth = offsets.hPadding;
    2525               0 :   float pctOutsideWidth = offsets.hPctPadding;
    2526                 : 
    2527               0 :   float pctTotal = 0.0f;
    2528                 : 
    2529               0 :   if (boxSizing == NS_STYLE_BOX_SIZING_PADDING) {
    2530               0 :     min += coordOutsideWidth;
    2531               0 :     result = NSCoordSaturatingAdd(result, coordOutsideWidth);
    2532               0 :     pctTotal += pctOutsideWidth;
    2533                 : 
    2534               0 :     coordOutsideWidth = 0;
    2535               0 :     pctOutsideWidth = 0.0f;
    2536                 :   }
    2537                 : 
    2538               0 :   coordOutsideWidth += offsets.hBorder;
    2539                 : 
    2540               0 :   if (boxSizing == NS_STYLE_BOX_SIZING_BORDER) {
    2541               0 :     min += coordOutsideWidth;
    2542               0 :     result = NSCoordSaturatingAdd(result, coordOutsideWidth);
    2543               0 :     pctTotal += pctOutsideWidth;
    2544                 : 
    2545               0 :     coordOutsideWidth = 0;
    2546               0 :     pctOutsideWidth = 0.0f;
    2547                 :   }
    2548                 : 
    2549               0 :   coordOutsideWidth += offsets.hMargin;
    2550               0 :   pctOutsideWidth += offsets.hPctMargin;
    2551                 : 
    2552               0 :   min += coordOutsideWidth;
    2553               0 :   result = NSCoordSaturatingAdd(result, coordOutsideWidth);
    2554               0 :   pctTotal += pctOutsideWidth;
    2555                 : 
    2556                 :   nscoord w;
    2557               0 :   if (GetAbsoluteCoord(styleWidth, w) ||
    2558                 :       GetIntrinsicCoord(styleWidth, aRenderingContext, aFrame,
    2559               0 :                         PROP_WIDTH, w)) {
    2560               0 :     result = AddPercents(aType, w + coordOutsideWidth, pctOutsideWidth);
    2561                 :   }
    2562               0 :   else if (aType == MIN_WIDTH &&
    2563                 :            // The only cases of coord-percent-calc() units that
    2564                 :            // GetAbsoluteCoord didn't handle are percent and calc()s
    2565                 :            // containing percent.
    2566               0 :            styleWidth.IsCoordPercentCalcUnit() &&
    2567               0 :            aFrame->IsFrameOfType(nsIFrame::eReplaced)) {
    2568                 :     // A percentage width on replaced elements means they can shrink to 0.
    2569               0 :     result = 0; // let |min| handle padding/border/margin
    2570                 :   }
    2571                 :   else {
    2572                 :     // NOTE: We could really do a lot better for percents and for some
    2573                 :     // cases of calc() containing percent (certainly including any where
    2574                 :     // the coefficient on the percent is positive and there are no max()
    2575                 :     // expressions).  However, doing better for percents wouldn't be
    2576                 :     // backwards compatible.
    2577               0 :     result = AddPercents(aType, result, pctTotal);
    2578                 :   }
    2579                 : 
    2580               0 :   if (haveFixedMaxWidth ||
    2581                 :       GetIntrinsicCoord(styleMaxWidth, aRenderingContext, aFrame,
    2582               0 :                         PROP_MAX_WIDTH, maxw)) {
    2583               0 :     maxw = AddPercents(aType, maxw + coordOutsideWidth, pctOutsideWidth);
    2584               0 :     if (result > maxw)
    2585               0 :       result = maxw;
    2586                 :   }
    2587                 : 
    2588               0 :   if (haveFixedMinWidth ||
    2589                 :       GetIntrinsicCoord(styleMinWidth, aRenderingContext, aFrame,
    2590               0 :                         PROP_MIN_WIDTH, minw)) {
    2591               0 :     minw = AddPercents(aType, minw + coordOutsideWidth, pctOutsideWidth);
    2592               0 :     if (result < minw)
    2593               0 :       result = minw;
    2594                 :   }
    2595                 : 
    2596               0 :   min = AddPercents(aType, min, pctTotal);
    2597               0 :   if (result < min)
    2598               0 :     result = min;
    2599                 : 
    2600               0 :   const nsStyleDisplay *disp = aFrame->GetStyleDisplay();
    2601               0 :   if (aFrame->IsThemed(disp)) {
    2602               0 :     nsIntSize size(0, 0);
    2603               0 :     bool canOverride = true;
    2604               0 :     nsPresContext *presContext = aFrame->PresContext();
    2605               0 :     presContext->GetTheme()->
    2606                 :       GetMinimumWidgetSize(aRenderingContext, aFrame, disp->mAppearance,
    2607               0 :                            &size, &canOverride);
    2608                 : 
    2609               0 :     nscoord themeWidth = presContext->DevPixelsToAppUnits(size.width);
    2610                 : 
    2611                 :     // GMWS() returns a border-box width
    2612               0 :     themeWidth += offsets.hMargin;
    2613               0 :     themeWidth = AddPercents(aType, themeWidth, offsets.hPctMargin);
    2614                 : 
    2615               0 :     if (themeWidth > result || !canOverride)
    2616               0 :       result = themeWidth;
    2617                 :   }
    2618                 : 
    2619                 : #ifdef DEBUG_INTRINSIC_WIDTH
    2620                 :   nsFrame::IndentBy(stdout, gNoiseIndent);
    2621                 :   static_cast<nsFrame*>(aFrame)->ListTag(stdout);
    2622                 :   printf(" %s intrinsic width for container is %d twips.\n",
    2623                 :          aType == MIN_WIDTH ? "min" : "pref", result);
    2624                 : #endif
    2625                 : 
    2626               0 :   return result;
    2627                 : }
    2628                 : 
    2629                 : /* static */ nscoord
    2630               0 : nsLayoutUtils::ComputeWidthDependentValue(
    2631                 :                  nscoord              aContainingBlockWidth,
    2632                 :                  const nsStyleCoord&  aCoord)
    2633                 : {
    2634               0 :   NS_WARN_IF_FALSE(aContainingBlockWidth != NS_UNCONSTRAINEDSIZE,
    2635                 :                    "have unconstrained width; this should only result from "
    2636                 :                    "very large sizes, not attempts at intrinsic width "
    2637                 :                    "calculation");
    2638                 : 
    2639               0 :   if (aCoord.IsCoordPercentCalcUnit()) {
    2640               0 :     return nsRuleNode::ComputeCoordPercentCalc(aCoord, aContainingBlockWidth);
    2641                 :   }
    2642               0 :   NS_ASSERTION(aCoord.GetUnit() == eStyleUnit_None ||
    2643                 :                aCoord.GetUnit() == eStyleUnit_Auto,
    2644                 :                "unexpected width value");
    2645               0 :   return 0;
    2646                 : }
    2647                 : 
    2648                 : /* static */ nscoord
    2649               0 : nsLayoutUtils::ComputeWidthValue(
    2650                 :                  nsRenderingContext* aRenderingContext,
    2651                 :                  nsIFrame*            aFrame,
    2652                 :                  nscoord              aContainingBlockWidth,
    2653                 :                  nscoord              aContentEdgeToBoxSizing,
    2654                 :                  nscoord              aBoxSizingToMarginEdge,
    2655                 :                  const nsStyleCoord&  aCoord)
    2656                 : {
    2657               0 :   NS_PRECONDITION(aFrame, "non-null frame expected");
    2658               0 :   NS_PRECONDITION(aRenderingContext, "non-null rendering context expected");
    2659               0 :   NS_WARN_IF_FALSE(aContainingBlockWidth != NS_UNCONSTRAINEDSIZE,
    2660                 :                    "have unconstrained width; this should only result from "
    2661                 :                    "very large sizes, not attempts at intrinsic width "
    2662                 :                    "calculation");
    2663               0 :   NS_PRECONDITION(aContainingBlockWidth >= 0,
    2664                 :                   "width less than zero");
    2665                 : 
    2666                 :   nscoord result;
    2667               0 :   if (aCoord.IsCoordPercentCalcUnit()) {
    2668               0 :     result = nsRuleNode::ComputeCoordPercentCalc(aCoord, aContainingBlockWidth);
    2669                 :     // The result of a calc() expression might be less than 0; we
    2670                 :     // should clamp at runtime (below).  (Percentages and coords that
    2671                 :     // are less than 0 have already been dropped by the parser.)
    2672               0 :     result -= aContentEdgeToBoxSizing;
    2673               0 :   } else if (eStyleUnit_Enumerated == aCoord.GetUnit()) {
    2674                 :     // If aFrame is a container for font size inflation, then shrink
    2675                 :     // wrapping inside of it should not apply font size inflation.
    2676               0 :     AutoMaybeNullInflationContainer an(aFrame);
    2677                 : 
    2678               0 :     PRInt32 val = aCoord.GetIntValue();
    2679               0 :     switch (val) {
    2680                 :       case NS_STYLE_WIDTH_MAX_CONTENT:
    2681               0 :         result = aFrame->GetPrefWidth(aRenderingContext);
    2682               0 :         NS_ASSERTION(result >= 0, "width less than zero");
    2683               0 :         break;
    2684                 :       case NS_STYLE_WIDTH_MIN_CONTENT:
    2685               0 :         result = aFrame->GetMinWidth(aRenderingContext);
    2686               0 :         NS_ASSERTION(result >= 0, "width less than zero");
    2687               0 :         break;
    2688                 :       case NS_STYLE_WIDTH_FIT_CONTENT:
    2689                 :         {
    2690               0 :           nscoord pref = aFrame->GetPrefWidth(aRenderingContext),
    2691               0 :                    min = aFrame->GetMinWidth(aRenderingContext),
    2692                 :                   fill = aContainingBlockWidth -
    2693               0 :                          (aBoxSizingToMarginEdge + aContentEdgeToBoxSizing);
    2694               0 :           result = NS_MAX(min, NS_MIN(pref, fill));
    2695               0 :           NS_ASSERTION(result >= 0, "width less than zero");
    2696                 :         }
    2697               0 :         break;
    2698                 :       case NS_STYLE_WIDTH_AVAILABLE:
    2699                 :         result = aContainingBlockWidth -
    2700               0 :                  (aBoxSizingToMarginEdge + aContentEdgeToBoxSizing);
    2701                 :     }
    2702                 :   } else {
    2703               0 :     NS_NOTREACHED("unexpected width value");
    2704               0 :     result = 0;
    2705                 :   }
    2706               0 :   if (result < 0)
    2707               0 :     result = 0;
    2708               0 :   return result;
    2709                 : }
    2710                 : 
    2711                 : 
    2712                 : /* static */ nscoord
    2713               0 : nsLayoutUtils::ComputeHeightDependentValue(
    2714                 :                  nscoord              aContainingBlockHeight,
    2715                 :                  const nsStyleCoord&  aCoord)
    2716                 : {
    2717                 :   // XXXldb Some callers explicitly check aContainingBlockHeight
    2718                 :   // against NS_AUTOHEIGHT *and* unit against eStyleUnit_Percent or
    2719                 :   // calc()s containing percents before calling this function.
    2720                 :   // However, it would be much more likely to catch problems without
    2721                 :   // the unit conditions.
    2722                 :   // XXXldb Many callers pass a non-'auto' containing block height when
    2723                 :   // according to CSS2.1 they should be passing 'auto'.
    2724               0 :   NS_PRECONDITION(NS_AUTOHEIGHT != aContainingBlockHeight ||
    2725                 :                   !aCoord.HasPercent(),
    2726                 :                   "unexpected containing block height");
    2727                 : 
    2728               0 :   if (aCoord.IsCoordPercentCalcUnit()) {
    2729               0 :     return nsRuleNode::ComputeCoordPercentCalc(aCoord, aContainingBlockHeight);
    2730                 :   }
    2731                 : 
    2732               0 :   NS_ASSERTION(aCoord.GetUnit() == eStyleUnit_None ||
    2733                 :                aCoord.GetUnit() == eStyleUnit_Auto,
    2734                 :                "unexpected height value");
    2735               0 :   return 0;
    2736                 : }
    2737                 : 
    2738                 : #define MULDIV(a,b,c) (nscoord(PRInt64(a) * PRInt64(b) / PRInt64(c)))
    2739                 : 
    2740                 : /* static */ nsSize
    2741               0 : nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(
    2742                 :                    nsRenderingContext* aRenderingContext, nsIFrame* aFrame,
    2743                 :                    const nsIFrame::IntrinsicSize& aIntrinsicSize,
    2744                 :                    nsSize aIntrinsicRatio, nsSize aCBSize,
    2745                 :                    nsSize aMargin, nsSize aBorder, nsSize aPadding)
    2746                 : {
    2747               0 :   const nsStylePosition *stylePos = aFrame->GetStylePosition();
    2748                 :   // Handle intrinsic sizes and their interaction with
    2749                 :   // {min-,max-,}{width,height} according to the rules in
    2750                 :   // http://www.w3.org/TR/CSS21/visudet.html#min-max-widths
    2751                 : 
    2752                 :   // Note: throughout the following section of the function, I avoid
    2753                 :   // a * (b / c) because of its reduced accuracy relative to a * b / c
    2754                 :   // or (a * b) / c (which are equivalent).
    2755                 : 
    2756               0 :   const bool isAutoWidth = stylePos->mWidth.GetUnit() == eStyleUnit_Auto;
    2757               0 :   const bool isAutoHeight = IsAutoHeight(stylePos->mHeight, aCBSize.height);
    2758                 : 
    2759               0 :   nsSize boxSizingAdjust(0,0);
    2760               0 :   switch (stylePos->mBoxSizing) {
    2761                 :     case NS_STYLE_BOX_SIZING_BORDER:
    2762               0 :       boxSizingAdjust += aBorder;
    2763                 :       // fall through
    2764                 :     case NS_STYLE_BOX_SIZING_PADDING:
    2765               0 :       boxSizingAdjust += aPadding;
    2766                 :   }
    2767                 :   nscoord boxSizingToMarginEdgeWidth =
    2768               0 :     aMargin.width + aBorder.width + aPadding.width - boxSizingAdjust.width;
    2769                 : 
    2770                 :   nscoord width, minWidth, maxWidth, height, minHeight, maxHeight;
    2771                 : 
    2772               0 :   if (!isAutoWidth) {
    2773                 :     width = nsLayoutUtils::ComputeWidthValue(aRenderingContext,
    2774                 :               aFrame, aCBSize.width, boxSizingAdjust.width,
    2775               0 :               boxSizingToMarginEdgeWidth, stylePos->mWidth);
    2776               0 :     NS_ASSERTION(width >= 0, "negative result from ComputeWidthValue");
    2777                 :   }
    2778                 : 
    2779               0 :   if (stylePos->mMaxWidth.GetUnit() != eStyleUnit_None) {
    2780                 :     maxWidth = nsLayoutUtils::ComputeWidthValue(aRenderingContext,
    2781                 :                  aFrame, aCBSize.width, boxSizingAdjust.width,
    2782               0 :                  boxSizingToMarginEdgeWidth, stylePos->mMaxWidth);
    2783               0 :     NS_ASSERTION(maxWidth >= 0, "negative result from ComputeWidthValue");
    2784                 :   } else {
    2785               0 :     maxWidth = nscoord_MAX;
    2786                 :   }
    2787                 : 
    2788                 :   minWidth = nsLayoutUtils::ComputeWidthValue(aRenderingContext,
    2789                 :                aFrame, aCBSize.width, boxSizingAdjust.width,
    2790               0 :                boxSizingToMarginEdgeWidth, stylePos->mMinWidth);
    2791               0 :   NS_ASSERTION(minWidth >= 0, "negative result from ComputeWidthValue");
    2792                 : 
    2793               0 :   if (!isAutoHeight) {
    2794                 :     height = nsLayoutUtils::
    2795               0 :       ComputeHeightValue(aCBSize.height, stylePos->mHeight) -
    2796               0 :       boxSizingAdjust.height;
    2797               0 :     if (height < 0)
    2798               0 :       height = 0;
    2799                 :   }
    2800                 : 
    2801               0 :   if (!IsAutoHeight(stylePos->mMaxHeight, aCBSize.height)) {
    2802                 :     maxHeight = nsLayoutUtils::
    2803               0 :       ComputeHeightValue(aCBSize.height, stylePos->mMaxHeight) -
    2804               0 :       boxSizingAdjust.height;
    2805               0 :     if (maxHeight < 0)
    2806               0 :       maxHeight = 0;
    2807                 :   } else {
    2808               0 :     maxHeight = nscoord_MAX;
    2809                 :   }
    2810                 : 
    2811               0 :   if (!IsAutoHeight(stylePos->mMinHeight, aCBSize.height)) {
    2812                 :     minHeight = nsLayoutUtils::
    2813               0 :       ComputeHeightValue(aCBSize.height, stylePos->mMinHeight) -
    2814               0 :       boxSizingAdjust.height;
    2815               0 :     if (minHeight < 0)
    2816               0 :       minHeight = 0;
    2817                 :   } else {
    2818               0 :     minHeight = 0;
    2819                 :   }
    2820                 : 
    2821                 :   // Resolve percentage intrinsic width/height as necessary:
    2822                 : 
    2823               0 :   NS_ASSERTION(aCBSize.width != NS_UNCONSTRAINEDSIZE,
    2824                 :                "Our containing block must not have unconstrained width!");
    2825                 : 
    2826                 :   bool hasIntrinsicWidth, hasIntrinsicHeight;
    2827                 :   nscoord intrinsicWidth, intrinsicHeight;
    2828                 : 
    2829               0 :   if (aIntrinsicSize.width.GetUnit() == eStyleUnit_Coord) {
    2830               0 :     hasIntrinsicWidth = true;
    2831               0 :     intrinsicWidth = aIntrinsicSize.width.GetCoordValue();
    2832               0 :     if (intrinsicWidth < 0)
    2833               0 :       intrinsicWidth = 0;
    2834                 :   } else {
    2835               0 :     NS_ASSERTION(aIntrinsicSize.width.GetUnit() == eStyleUnit_None,
    2836                 :                  "unexpected unit");
    2837               0 :     hasIntrinsicWidth = false;
    2838               0 :     intrinsicWidth = 0;
    2839                 :   }
    2840                 : 
    2841               0 :   if (aIntrinsicSize.height.GetUnit() == eStyleUnit_Coord) {
    2842               0 :     hasIntrinsicHeight = true;
    2843               0 :     intrinsicHeight = aIntrinsicSize.height.GetCoordValue();
    2844               0 :     if (intrinsicHeight < 0)
    2845               0 :       intrinsicHeight = 0;
    2846                 :   } else {
    2847               0 :     NS_ASSERTION(aIntrinsicSize.height.GetUnit() == eStyleUnit_None,
    2848                 :                  "unexpected unit");
    2849               0 :     hasIntrinsicHeight = false;
    2850               0 :     intrinsicHeight = 0;
    2851                 :   }
    2852                 : 
    2853               0 :   NS_ASSERTION(aIntrinsicRatio.width >= 0 && aIntrinsicRatio.height >= 0,
    2854                 :                "Intrinsic ratio has a negative component!");
    2855                 : 
    2856                 :   // Now calculate the used values for width and height:
    2857                 : 
    2858               0 :   if (isAutoWidth) {
    2859               0 :     if (isAutoHeight) {
    2860                 : 
    2861                 :       // 'auto' width, 'auto' height
    2862                 : 
    2863                 :       // Get tentative values - CSS 2.1 sections 10.3.2 and 10.6.2:
    2864                 : 
    2865                 :       nscoord tentWidth, tentHeight;
    2866                 : 
    2867               0 :       if (hasIntrinsicWidth) {
    2868               0 :         tentWidth = intrinsicWidth;
    2869               0 :       } else if (hasIntrinsicHeight && aIntrinsicRatio.height > 0) {
    2870               0 :         tentWidth = MULDIV(intrinsicHeight, aIntrinsicRatio.width, aIntrinsicRatio.height);
    2871               0 :       } else if (aIntrinsicRatio.width > 0) {
    2872               0 :         tentWidth = aCBSize.width - boxSizingToMarginEdgeWidth; // XXX scrollbar?
    2873               0 :         if (tentWidth < 0) tentWidth = 0;
    2874                 :       } else {
    2875               0 :         tentWidth = nsPresContext::CSSPixelsToAppUnits(300);
    2876                 :       }
    2877                 : 
    2878               0 :       if (hasIntrinsicHeight) {
    2879               0 :         tentHeight = intrinsicHeight;
    2880               0 :       } else if (aIntrinsicRatio.width > 0) {
    2881               0 :         tentHeight = MULDIV(tentWidth, aIntrinsicRatio.height, aIntrinsicRatio.width);
    2882                 :       } else {
    2883               0 :         tentHeight = nsPresContext::CSSPixelsToAppUnits(150);
    2884                 :       }
    2885                 : 
    2886                 :       return ComputeAutoSizeWithIntrinsicDimensions(minWidth, minHeight,
    2887                 :                                                     maxWidth, maxHeight,
    2888               0 :                                                     tentWidth, tentHeight);
    2889                 :     } else {
    2890                 : 
    2891                 :       // 'auto' width, non-'auto' height
    2892               0 :       height = NS_CSS_MINMAX(height, minHeight, maxHeight);
    2893               0 :       if (aIntrinsicRatio.height > 0) {
    2894               0 :         width = MULDIV(height, aIntrinsicRatio.width, aIntrinsicRatio.height);
    2895               0 :       } else if (hasIntrinsicWidth) {
    2896               0 :         width = intrinsicWidth;
    2897                 :       } else {
    2898               0 :         width = nsPresContext::CSSPixelsToAppUnits(300);
    2899                 :       }
    2900               0 :       width = NS_CSS_MINMAX(width, minWidth, maxWidth);
    2901                 : 
    2902                 :     }
    2903                 :   } else {
    2904               0 :     if (isAutoHeight) {
    2905                 : 
    2906                 :       // non-'auto' width, 'auto' height
    2907               0 :       width = NS_CSS_MINMAX(width, minWidth, maxWidth);
    2908               0 :       if (aIntrinsicRatio.width > 0) {
    2909               0 :         height = MULDIV(width, aIntrinsicRatio.height, aIntrinsicRatio.width);
    2910               0 :       } else if (hasIntrinsicHeight) {
    2911               0 :         height = intrinsicHeight;
    2912                 :       } else {
    2913               0 :         height = nsPresContext::CSSPixelsToAppUnits(150);
    2914                 :       }
    2915               0 :       height = NS_CSS_MINMAX(height, minHeight, maxHeight);
    2916                 : 
    2917                 :     } else {
    2918                 : 
    2919                 :       // non-'auto' width, non-'auto' height
    2920               0 :       width = NS_CSS_MINMAX(width, minWidth, maxWidth);
    2921               0 :       height = NS_CSS_MINMAX(height, minHeight, maxHeight);
    2922                 : 
    2923                 :     }
    2924                 :   }
    2925                 : 
    2926               0 :   return nsSize(width, height);
    2927                 : }
    2928                 : 
    2929                 : nsSize
    2930               0 : nsLayoutUtils::ComputeAutoSizeWithIntrinsicDimensions(nscoord minWidth, nscoord minHeight,
    2931                 :                                                       nscoord maxWidth, nscoord maxHeight,
    2932                 :                                                       nscoord tentWidth, nscoord tentHeight)
    2933                 : {
    2934                 :   // Now apply min/max-width/height - CSS 2.1 sections 10.4 and 10.7:
    2935                 : 
    2936               0 :   if (minWidth > maxWidth)
    2937               0 :     maxWidth = minWidth;
    2938               0 :   if (minHeight > maxHeight)
    2939               0 :     maxHeight = minHeight;
    2940                 : 
    2941                 :   nscoord heightAtMaxWidth, heightAtMinWidth,
    2942                 :           widthAtMaxHeight, widthAtMinHeight;
    2943                 : 
    2944               0 :   if (tentWidth > 0) {
    2945               0 :     heightAtMaxWidth = MULDIV(maxWidth, tentHeight, tentWidth);
    2946               0 :     if (heightAtMaxWidth < minHeight)
    2947               0 :       heightAtMaxWidth = minHeight;
    2948               0 :     heightAtMinWidth = MULDIV(minWidth, tentHeight, tentWidth);
    2949               0 :     if (heightAtMinWidth > maxHeight)
    2950               0 :       heightAtMinWidth = maxHeight;
    2951                 :   } else {
    2952               0 :     heightAtMaxWidth = heightAtMinWidth = NS_CSS_MINMAX(tentHeight, minHeight, maxHeight);
    2953                 :   }
    2954                 : 
    2955               0 :   if (tentHeight > 0) {
    2956               0 :     widthAtMaxHeight = MULDIV(maxHeight, tentWidth, tentHeight);
    2957               0 :     if (widthAtMaxHeight < minWidth)
    2958               0 :       widthAtMaxHeight = minWidth;
    2959               0 :     widthAtMinHeight = MULDIV(minHeight, tentWidth, tentHeight);
    2960               0 :     if (widthAtMinHeight > maxWidth)
    2961               0 :       widthAtMinHeight = maxWidth;
    2962                 :   } else {
    2963               0 :     widthAtMaxHeight = widthAtMinHeight = NS_CSS_MINMAX(tentWidth, minWidth, maxWidth);
    2964                 :   }
    2965                 : 
    2966                 :   // The table at http://www.w3.org/TR/CSS21/visudet.html#min-max-widths :
    2967                 : 
    2968                 :   nscoord width, height;
    2969                 : 
    2970               0 :   if (tentWidth > maxWidth) {
    2971               0 :     if (tentHeight > maxHeight) {
    2972               0 :       if (PRInt64(maxWidth) * PRInt64(tentHeight) <=
    2973                 :           PRInt64(maxHeight) * PRInt64(tentWidth)) {
    2974               0 :         width = maxWidth;
    2975               0 :         height = heightAtMaxWidth;
    2976                 :       } else {
    2977               0 :         width = widthAtMaxHeight;
    2978               0 :         height = maxHeight;
    2979                 :       }
    2980                 :     } else {
    2981                 :       // This also covers "(w > max-width) and (h < min-height)" since in
    2982                 :       // that case (max-width/w < 1), and with (h < min-height):
    2983                 :       //   max(max-width * h/w, min-height) == min-height
    2984               0 :       width = maxWidth;
    2985               0 :       height = heightAtMaxWidth;
    2986                 :     }
    2987               0 :   } else if (tentWidth < minWidth) {
    2988               0 :     if (tentHeight < minHeight) {
    2989               0 :       if (PRInt64(minWidth) * PRInt64(tentHeight) <=
    2990                 :           PRInt64(minHeight) * PRInt64(tentWidth)) {
    2991               0 :         width = widthAtMinHeight;
    2992               0 :         height = minHeight;
    2993                 :       } else {
    2994               0 :         width = minWidth;
    2995               0 :         height = heightAtMinWidth;
    2996                 :       }
    2997                 :     } else {
    2998                 :       // This also covers "(w < min-width) and (h > max-height)" since in
    2999                 :       // that case (min-width/w > 1), and with (h > max-height):
    3000                 :       //   min(min-width * h/w, max-height) == max-height
    3001               0 :       width = minWidth;
    3002               0 :       height = heightAtMinWidth;
    3003                 :     }
    3004                 :   } else {
    3005               0 :     if (tentHeight > maxHeight) {
    3006               0 :       width = widthAtMaxHeight;
    3007               0 :       height = maxHeight;
    3008               0 :     } else if (tentHeight < minHeight) {
    3009               0 :       width = widthAtMinHeight;
    3010               0 :       height = minHeight;
    3011                 :     } else {
    3012               0 :       width = tentWidth;
    3013               0 :       height = tentHeight;
    3014                 :     }
    3015                 :   }
    3016                 : 
    3017               0 :   return nsSize(width, height);
    3018                 : }
    3019                 : 
    3020                 : /* static */ nscoord
    3021               0 : nsLayoutUtils::MinWidthFromInline(nsIFrame* aFrame,
    3022                 :                                   nsRenderingContext* aRenderingContext)
    3023                 : {
    3024               0 :   NS_ASSERTION(!nsLayoutUtils::IsContainerForFontSizeInflation(aFrame),
    3025                 :                "should not be container for font size inflation");
    3026                 : 
    3027               0 :   nsIFrame::InlineMinWidthData data;
    3028               0 :   DISPLAY_MIN_WIDTH(aFrame, data.prevLines);
    3029               0 :   aFrame->AddInlineMinWidth(aRenderingContext, &data);
    3030               0 :   data.ForceBreak(aRenderingContext);
    3031               0 :   return data.prevLines;
    3032                 : }
    3033                 : 
    3034                 : /* static */ nscoord
    3035               0 : nsLayoutUtils::PrefWidthFromInline(nsIFrame* aFrame,
    3036                 :                                    nsRenderingContext* aRenderingContext)
    3037                 : {
    3038               0 :   NS_ASSERTION(!nsLayoutUtils::IsContainerForFontSizeInflation(aFrame),
    3039                 :                "should not be container for font size inflation");
    3040                 : 
    3041               0 :   nsIFrame::InlinePrefWidthData data;
    3042               0 :   DISPLAY_PREF_WIDTH(aFrame, data.prevLines);
    3043               0 :   aFrame->AddInlinePrefWidth(aRenderingContext, &data);
    3044               0 :   data.ForceBreak(aRenderingContext);
    3045               0 :   return data.prevLines;
    3046                 : }
    3047                 : 
    3048                 : static nscolor
    3049               0 : DarkenColor(nscolor aColor)
    3050                 : {
    3051                 :   PRUint16  hue, sat, value;
    3052                 :   PRUint8 alpha;
    3053                 : 
    3054                 :   // convert the RBG to HSV so we can get the lightness (which is the v)
    3055               0 :   NS_RGB2HSV(aColor, hue, sat, value, alpha);
    3056                 : 
    3057                 :   // The goal here is to send white to black while letting colored
    3058                 :   // stuff stay colored... So we adopt the following approach.
    3059                 :   // Something with sat = 0 should end up with value = 0.  Something
    3060                 :   // with a high sat can end up with a high value and it's ok.... At
    3061                 :   // the same time, we don't want to make things lighter.  Do
    3062                 :   // something simple, since it seems to work.
    3063               0 :   if (value > sat) {
    3064               0 :     value = sat;
    3065                 :     // convert this color back into the RGB color space.
    3066               0 :     NS_HSV2RGB(aColor, hue, sat, value, alpha);
    3067                 :   }
    3068               0 :   return aColor;
    3069                 : }
    3070                 : 
    3071                 : // Check whether we should darken text/decoration colors. We need to do this if
    3072                 : // background images and colors are being suppressed, because that means
    3073                 : // light text will not be visible against the (presumed light-colored) background.
    3074                 : static bool
    3075               0 : ShouldDarkenColors(nsPresContext* aPresContext)
    3076                 : {
    3077               0 :   return !aPresContext->GetBackgroundColorDraw() &&
    3078               0 :          !aPresContext->GetBackgroundImageDraw();
    3079                 : }
    3080                 : 
    3081                 : nscolor
    3082               0 : nsLayoutUtils::GetColor(nsIFrame* aFrame, nsCSSProperty aProperty)
    3083                 : {
    3084               0 :   nscolor color = aFrame->GetVisitedDependentColor(aProperty);
    3085               0 :   if (ShouldDarkenColors(aFrame->PresContext())) {
    3086               0 :     color = DarkenColor(color);
    3087                 :   }
    3088               0 :   return color;
    3089                 : }
    3090                 : 
    3091                 : gfxFloat
    3092               0 : nsLayoutUtils::GetSnappedBaselineY(nsIFrame* aFrame, gfxContext* aContext,
    3093                 :                                    nscoord aY, nscoord aAscent)
    3094                 : {
    3095               0 :   gfxFloat appUnitsPerDevUnit = aFrame->PresContext()->AppUnitsPerDevPixel();
    3096               0 :   gfxFloat baseline = gfxFloat(aY) + aAscent;
    3097               0 :   gfxRect putativeRect(0, baseline/appUnitsPerDevUnit, 1, 1);
    3098               0 :   if (!aContext->UserToDevicePixelSnapped(putativeRect, true))
    3099               0 :     return baseline;
    3100               0 :   return aContext->DeviceToUser(putativeRect.TopLeft()).y * appUnitsPerDevUnit;
    3101                 : }
    3102                 : 
    3103                 : void
    3104               0 : nsLayoutUtils::DrawString(const nsIFrame*      aFrame,
    3105                 :                           nsRenderingContext* aContext,
    3106                 :                           const PRUnichar*     aString,
    3107                 :                           PRInt32              aLength,
    3108                 :                           nsPoint              aPoint,
    3109                 :                           PRUint8              aDirection)
    3110                 : {
    3111                 : #ifdef IBMBIDI
    3112               0 :   nsresult rv = NS_ERROR_FAILURE;
    3113               0 :   nsPresContext* presContext = aFrame->PresContext();
    3114               0 :   if (presContext->BidiEnabled()) {
    3115               0 :     if (aDirection == NS_STYLE_DIRECTION_INHERIT) {
    3116               0 :       aDirection = aFrame->GetStyleVisibility()->mDirection;
    3117                 :     }
    3118                 :     nsBidiDirection direction =
    3119                 :       (NS_STYLE_DIRECTION_RTL == aDirection) ?
    3120               0 :       NSBIDI_RTL : NSBIDI_LTR;
    3121                 :     rv = nsBidiPresUtils::RenderText(aString, aLength, direction,
    3122                 :                                      presContext, *aContext, *aContext,
    3123               0 :                                      aPoint.x, aPoint.y);
    3124                 :   }
    3125               0 :   if (NS_FAILED(rv))
    3126                 : #endif // IBMBIDI
    3127                 :   {
    3128               0 :     aContext->SetTextRunRTL(false);
    3129               0 :     aContext->DrawString(aString, aLength, aPoint.x, aPoint.y);
    3130                 :   }
    3131               0 : }
    3132                 : 
    3133                 : nscoord
    3134               0 : nsLayoutUtils::GetStringWidth(const nsIFrame*      aFrame,
    3135                 :                               nsRenderingContext* aContext,
    3136                 :                               const PRUnichar*     aString,
    3137                 :                               PRInt32              aLength)
    3138                 : {
    3139                 : #ifdef IBMBIDI
    3140               0 :   nsPresContext* presContext = aFrame->PresContext();
    3141               0 :   if (presContext->BidiEnabled()) {
    3142               0 :     const nsStyleVisibility* vis = aFrame->GetStyleVisibility();
    3143                 :     nsBidiDirection direction =
    3144                 :       (NS_STYLE_DIRECTION_RTL == vis->mDirection) ?
    3145               0 :       NSBIDI_RTL : NSBIDI_LTR;
    3146                 :     return nsBidiPresUtils::MeasureTextWidth(aString, aLength,
    3147               0 :                                              direction, presContext, *aContext);
    3148                 :   }
    3149                 : #endif // IBMBIDI
    3150               0 :   aContext->SetTextRunRTL(false);
    3151               0 :   return aContext->GetWidth(aString, aLength);
    3152                 : }
    3153                 : 
    3154                 : /* static */ void
    3155               0 : nsLayoutUtils::PaintTextShadow(const nsIFrame* aFrame,
    3156                 :                                nsRenderingContext* aContext,
    3157                 :                                const nsRect& aTextRect,
    3158                 :                                const nsRect& aDirtyRect,
    3159                 :                                const nscolor& aForegroundColor,
    3160                 :                                TextShadowCallback aCallback,
    3161                 :                                void* aCallbackData)
    3162                 : {
    3163               0 :   const nsStyleText* textStyle = aFrame->GetStyleText();
    3164               0 :   if (!textStyle->mTextShadow)
    3165               0 :     return;
    3166                 : 
    3167                 :   // Text shadow happens with the last value being painted at the back,
    3168                 :   // ie. it is painted first.
    3169               0 :   gfxContext* aDestCtx = aContext->ThebesContext();
    3170               0 :   for (PRUint32 i = textStyle->mTextShadow->Length(); i > 0; --i) {
    3171               0 :     nsCSSShadowItem* shadowDetails = textStyle->mTextShadow->ShadowAt(i - 1);
    3172                 :     nsPoint shadowOffset(shadowDetails->mXOffset,
    3173               0 :                          shadowDetails->mYOffset);
    3174               0 :     nscoord blurRadius = NS_MAX(shadowDetails->mRadius, 0);
    3175                 : 
    3176               0 :     nsRect shadowRect(aTextRect);
    3177               0 :     shadowRect.MoveBy(shadowOffset);
    3178                 : 
    3179               0 :     nsPresContext* presCtx = aFrame->PresContext();
    3180               0 :     nsContextBoxBlur contextBoxBlur;
    3181                 :     gfxContext* shadowContext = contextBoxBlur.Init(shadowRect, 0, blurRadius,
    3182               0 :                                                     presCtx->AppUnitsPerDevPixel(),
    3183               0 :                                                     aDestCtx, aDirtyRect, nsnull);
    3184               0 :     if (!shadowContext)
    3185               0 :       continue;
    3186                 : 
    3187                 :     nscolor shadowColor;
    3188               0 :     if (shadowDetails->mHasColor)
    3189               0 :       shadowColor = shadowDetails->mColor;
    3190                 :     else
    3191               0 :       shadowColor = aForegroundColor;
    3192                 : 
    3193                 :     // Conjure an nsRenderingContext from a gfxContext for drawing the text
    3194                 :     // to blur.
    3195               0 :     nsRefPtr<nsRenderingContext> renderingContext = new nsRenderingContext();
    3196               0 :     renderingContext->Init(presCtx->DeviceContext(), shadowContext);
    3197                 : 
    3198               0 :     aDestCtx->Save();
    3199               0 :     aDestCtx->NewPath();
    3200               0 :     aDestCtx->SetColor(gfxRGBA(shadowColor));
    3201                 : 
    3202                 :     // The callback will draw whatever we want to blur as a shadow.
    3203               0 :     aCallback(renderingContext, shadowOffset, shadowColor, aCallbackData);
    3204                 : 
    3205               0 :     contextBoxBlur.DoPaint();
    3206               0 :     aDestCtx->Restore();
    3207                 :   }
    3208                 : }
    3209                 : 
    3210                 : /* static */ nscoord
    3211               0 : nsLayoutUtils::GetCenteredFontBaseline(nsFontMetrics* aFontMetrics,
    3212                 :                                        nscoord         aLineHeight)
    3213                 : {
    3214               0 :   nscoord fontAscent = aFontMetrics->MaxAscent();
    3215               0 :   nscoord fontHeight = aFontMetrics->MaxHeight();
    3216                 : 
    3217               0 :   nscoord leading = aLineHeight - fontHeight;
    3218               0 :   return fontAscent + leading/2;
    3219                 : }
    3220                 : 
    3221                 : 
    3222                 : /* static */ bool
    3223               0 : nsLayoutUtils::GetFirstLineBaseline(const nsIFrame* aFrame, nscoord* aResult)
    3224                 : {
    3225                 :   LinePosition position;
    3226               0 :   if (!GetFirstLinePosition(aFrame, &position))
    3227               0 :     return false;
    3228               0 :   *aResult = position.mBaseline;
    3229               0 :   return true;
    3230                 : }
    3231                 : 
    3232                 : /* static */ bool
    3233               0 : nsLayoutUtils::GetFirstLinePosition(const nsIFrame* aFrame,
    3234                 :                                     LinePosition* aResult)
    3235                 : {
    3236               0 :   const nsBlockFrame* block = nsLayoutUtils::GetAsBlock(const_cast<nsIFrame*>(aFrame));
    3237               0 :   if (!block) {
    3238                 :     // For the first-line baseline we also have to check for a table, and if
    3239                 :     // so, use the baseline of its first row.
    3240               0 :     nsIAtom* fType = aFrame->GetType();
    3241               0 :     if (fType == nsGkAtoms::tableOuterFrame) {
    3242               0 :       aResult->mTop = 0;
    3243               0 :       aResult->mBaseline = aFrame->GetBaseline();
    3244                 :       // This is what we want for the list bullet caller; not sure if
    3245                 :       // other future callers will want the same.
    3246               0 :       aResult->mBottom = aFrame->GetSize().height;
    3247               0 :       return true;
    3248                 :     }
    3249                 : 
    3250                 :     // For first-line baselines, we have to consider scroll frames.
    3251               0 :     if (fType == nsGkAtoms::scrollFrame) {
    3252               0 :       nsIScrollableFrame *sFrame = do_QueryFrame(const_cast<nsIFrame*>(aFrame));
    3253               0 :       if (!sFrame) {
    3254               0 :         NS_NOTREACHED("not scroll frame");
    3255                 :       }
    3256                 :       LinePosition kidPosition;
    3257               0 :       if (GetFirstLinePosition(sFrame->GetScrolledFrame(), &kidPosition)) {
    3258                 :         // Consider only the border and padding that contributes to the
    3259                 :         // kid's position, not the scrolling, so we get the initial
    3260                 :         // position.
    3261               0 :         *aResult = kidPosition + aFrame->GetUsedBorderAndPadding().top;
    3262               0 :         return true;
    3263                 :       }
    3264               0 :       return false;
    3265                 :     }
    3266                 : 
    3267               0 :     if (fType == nsGkAtoms::fieldSetFrame) {
    3268                 :       LinePosition kidPosition;
    3269               0 :       nsIFrame* kid = aFrame->GetFirstPrincipalChild();
    3270                 :       // kid might be a legend frame here, but that's ok.
    3271               0 :       if (GetFirstLinePosition(kid, &kidPosition)) {
    3272               0 :         *aResult = kidPosition + kid->GetPosition().y;
    3273               0 :         return true;
    3274                 :       }
    3275               0 :       return false;
    3276                 :     }
    3277                 : 
    3278                 :     // No baseline.
    3279               0 :     return false;
    3280                 :   }
    3281                 : 
    3282               0 :   for (nsBlockFrame::const_line_iterator line = block->begin_lines(),
    3283               0 :                                      line_end = block->end_lines();
    3284                 :        line != line_end; ++line) {
    3285               0 :     if (line->IsBlock()) {
    3286               0 :       nsIFrame *kid = line->mFirstChild;
    3287                 :       LinePosition kidPosition;
    3288               0 :       if (GetFirstLinePosition(kid, &kidPosition)) {
    3289               0 :         *aResult = kidPosition + kid->GetPosition().y;
    3290               0 :         return true;
    3291                 :       }
    3292                 :     } else {
    3293                 :       // XXX Is this the right test?  We have some bogus empty lines
    3294                 :       // floating around, but IsEmpty is perhaps too weak.
    3295               0 :       if (line->GetHeight() != 0 || !line->IsEmpty()) {
    3296               0 :         nscoord top = line->mBounds.y;
    3297               0 :         aResult->mTop = top;
    3298               0 :         aResult->mBaseline = top + line->GetAscent();
    3299               0 :         aResult->mBottom = top + line->GetHeight();
    3300               0 :         return true;
    3301                 :       }
    3302                 :     }
    3303                 :   }
    3304               0 :   return false;
    3305                 : }
    3306                 : 
    3307                 : /* static */ bool
    3308               0 : nsLayoutUtils::GetLastLineBaseline(const nsIFrame* aFrame, nscoord* aResult)
    3309                 : {
    3310               0 :   const nsBlockFrame* block = nsLayoutUtils::GetAsBlock(const_cast<nsIFrame*>(aFrame));
    3311               0 :   if (!block)
    3312                 :     // No baseline.  (We intentionally don't descend into scroll frames.)
    3313               0 :     return false;
    3314                 : 
    3315               0 :   for (nsBlockFrame::const_reverse_line_iterator line = block->rbegin_lines(),
    3316               0 :                                              line_end = block->rend_lines();
    3317                 :        line != line_end; ++line) {
    3318               0 :     if (line->IsBlock()) {
    3319               0 :       nsIFrame *kid = line->mFirstChild;
    3320                 :       nscoord kidBaseline;
    3321               0 :       if (GetLastLineBaseline(kid, &kidBaseline)) {
    3322               0 :         *aResult = kidBaseline + kid->GetPosition().y;
    3323               0 :         return true;
    3324               0 :       } else if (kid->GetType() == nsGkAtoms::scrollFrame) {
    3325                 :         // Use the bottom of the scroll frame.
    3326                 :         // XXX CSS2.1 really doesn't say what to do here.
    3327               0 :         *aResult = kid->GetRect().YMost();
    3328               0 :         return true;
    3329                 :       }
    3330                 :     } else {
    3331                 :       // XXX Is this the right test?  We have some bogus empty lines
    3332                 :       // floating around, but IsEmpty is perhaps too weak.
    3333               0 :       if (line->GetHeight() != 0 || !line->IsEmpty()) {
    3334               0 :         *aResult = line->mBounds.y + line->GetAscent();
    3335               0 :         return true;
    3336                 :       }
    3337                 :     }
    3338                 :   }
    3339               0 :   return false;
    3340                 : }
    3341                 : 
    3342                 : static nscoord
    3343               0 : CalculateBlockContentBottom(nsBlockFrame* aFrame)
    3344                 : {
    3345               0 :   NS_PRECONDITION(aFrame, "null ptr");
    3346                 : 
    3347               0 :   nscoord contentBottom = 0;
    3348                 : 
    3349               0 :   for (nsBlockFrame::line_iterator line = aFrame->begin_lines(),
    3350               0 :                                    line_end = aFrame->end_lines();
    3351                 :        line != line_end; ++line) {
    3352               0 :     if (line->IsBlock()) {
    3353               0 :       nsIFrame* child = line->mFirstChild;
    3354               0 :       nscoord offset = child->GetRect().y - child->GetRelativeOffset().y;
    3355                 :       contentBottom = NS_MAX(contentBottom,
    3356               0 :                         nsLayoutUtils::CalculateContentBottom(child) + offset);
    3357                 :     }
    3358                 :     else {
    3359               0 :       contentBottom = NS_MAX(contentBottom, line->mBounds.YMost());
    3360                 :     }
    3361                 :   }
    3362               0 :   return contentBottom;
    3363                 : }
    3364                 : 
    3365                 : /* static */ nscoord
    3366               0 : nsLayoutUtils::CalculateContentBottom(nsIFrame* aFrame)
    3367                 : {
    3368               0 :   NS_PRECONDITION(aFrame, "null ptr");
    3369                 : 
    3370               0 :   nscoord contentBottom = aFrame->GetRect().height;
    3371                 : 
    3372                 :   // We want scrollable overflow rather than visual because this
    3373                 :   // calculation is intended to affect layout.
    3374               0 :   if (aFrame->GetScrollableOverflowRect().height > contentBottom) {
    3375                 :     nsIFrame::ChildListIDs skip(nsIFrame::kOverflowList |
    3376                 :                                 nsIFrame::kExcessOverflowContainersList |
    3377               0 :                                 nsIFrame::kOverflowOutOfFlowList);
    3378               0 :     nsBlockFrame* blockFrame = GetAsBlock(aFrame);
    3379               0 :     if (blockFrame) {
    3380                 :       contentBottom =
    3381               0 :         NS_MAX(contentBottom, CalculateBlockContentBottom(blockFrame));
    3382               0 :       skip |= nsIFrame::kPrincipalList;
    3383                 :     }
    3384               0 :     nsIFrame::ChildListIterator lists(aFrame);
    3385               0 :     for (; !lists.IsDone(); lists.Next()) {
    3386               0 :       if (!skip.Contains(lists.CurrentID())) {
    3387               0 :         nsFrameList::Enumerator childFrames(lists.CurrentList()); 
    3388               0 :         for (; !childFrames.AtEnd(); childFrames.Next()) {
    3389               0 :           nsIFrame* child = childFrames.get();
    3390               0 :           nscoord offset = child->GetRect().y - child->GetRelativeOffset().y;
    3391                 :           contentBottom = NS_MAX(contentBottom,
    3392               0 :                                  CalculateContentBottom(child) + offset);
    3393                 :         }
    3394                 :       }
    3395                 :     }
    3396                 :   }
    3397               0 :   return contentBottom;
    3398                 : }
    3399                 : 
    3400                 : /* static */ nsIFrame*
    3401               0 : nsLayoutUtils::GetClosestLayer(nsIFrame* aFrame)
    3402                 : {
    3403                 :   nsIFrame* layer;
    3404               0 :   for (layer = aFrame; layer; layer = layer->GetParent()) {
    3405               0 :     if (layer->GetStyleDisplay()->IsPositioned() ||
    3406               0 :         (layer->GetParent() &&
    3407               0 :           layer->GetParent()->GetType() == nsGkAtoms::scrollFrame))
    3408               0 :       break;
    3409                 :   }
    3410               0 :   if (layer)
    3411               0 :     return layer;
    3412               0 :   return aFrame->PresContext()->PresShell()->FrameManager()->GetRootFrame();
    3413                 : }
    3414                 : 
    3415                 : GraphicsFilter
    3416               0 : nsLayoutUtils::GetGraphicsFilterForFrame(nsIFrame* aForFrame)
    3417                 : {
    3418               0 :   GraphicsFilter defaultFilter = gfxPattern::FILTER_GOOD;
    3419               0 :   nsIFrame *frame = nsCSSRendering::IsCanvasFrame(aForFrame) ?
    3420               0 :     nsCSSRendering::FindBackgroundStyleFrame(aForFrame) : aForFrame;
    3421                 : 
    3422               0 :   switch (frame->GetStyleSVG()->mImageRendering) {
    3423                 :   case NS_STYLE_IMAGE_RENDERING_OPTIMIZESPEED:
    3424               0 :     return gfxPattern::FILTER_FAST;
    3425                 :   case NS_STYLE_IMAGE_RENDERING_OPTIMIZEQUALITY:
    3426               0 :     return gfxPattern::FILTER_BEST;
    3427                 :   case NS_STYLE_IMAGE_RENDERING_CRISPEDGES:
    3428               0 :     return gfxPattern::FILTER_NEAREST;
    3429                 :   default:
    3430               0 :     return defaultFilter;
    3431                 :   }
    3432                 : }
    3433                 : 
    3434                 : /**
    3435                 :  * Given an image being drawn into an appunit coordinate system, and
    3436                 :  * a point in that coordinate system, map the point back into image
    3437                 :  * pixel space.
    3438                 :  * @param aSize the size of the image, in pixels
    3439                 :  * @param aDest the rectangle that the image is being mapped into
    3440                 :  * @param aPt a point in the same coordinate system as the rectangle
    3441                 :  */
    3442                 : static gfxPoint
    3443               0 : MapToFloatImagePixels(const gfxSize& aSize,
    3444                 :                       const gfxRect& aDest, const gfxPoint& aPt)
    3445                 : {
    3446               0 :   return gfxPoint(((aPt.x - aDest.X())*aSize.width)/aDest.Width(),
    3447               0 :                   ((aPt.y - aDest.Y())*aSize.height)/aDest.Height());
    3448                 : }
    3449                 : 
    3450                 : /**
    3451                 :  * Given an image being drawn into an pixel-based coordinate system, and
    3452                 :  * a point in image space, map the point into the pixel-based coordinate
    3453                 :  * system.
    3454                 :  * @param aSize the size of the image, in pixels
    3455                 :  * @param aDest the rectangle that the image is being mapped into
    3456                 :  * @param aPt a point in image space
    3457                 :  */
    3458                 : static gfxPoint
    3459               0 : MapToFloatUserPixels(const gfxSize& aSize,
    3460                 :                      const gfxRect& aDest, const gfxPoint& aPt)
    3461                 : {
    3462               0 :   return gfxPoint(aPt.x*aDest.Width()/aSize.width + aDest.X(),
    3463               0 :                   aPt.y*aDest.Height()/aSize.height + aDest.Y());
    3464                 : }
    3465                 : 
    3466                 : /* static */ gfxRect
    3467               0 : nsLayoutUtils::RectToGfxRect(const nsRect& aRect, PRInt32 aAppUnitsPerDevPixel)
    3468                 : {
    3469                 :   return gfxRect(gfxFloat(aRect.x) / aAppUnitsPerDevPixel,
    3470                 :                  gfxFloat(aRect.y) / aAppUnitsPerDevPixel,
    3471                 :                  gfxFloat(aRect.width) / aAppUnitsPerDevPixel,
    3472               0 :                  gfxFloat(aRect.height) / aAppUnitsPerDevPixel);
    3473                 : }
    3474                 : 
    3475                 : struct SnappedImageDrawingParameters {
    3476                 :   // A transform from either device space or user space (depending on mResetCTM)
    3477                 :   // to image space
    3478                 :   gfxMatrix mUserSpaceToImageSpace;
    3479                 :   // A device-space, pixel-aligned rectangle to fill
    3480                 :   gfxRect mFillRect;
    3481                 :   // A pixel rectangle in tiled image space outside of which gfx should not
    3482                 :   // sample (using EXTEND_PAD as necessary)
    3483                 :   nsIntRect mSubimage;
    3484                 :   // Whether there's anything to draw at all
    3485                 :   bool mShouldDraw;
    3486                 :   // true iff the CTM of the rendering context needs to be reset to the
    3487                 :   // identity matrix before drawing
    3488                 :   bool mResetCTM;
    3489                 : 
    3490               0 :   SnappedImageDrawingParameters()
    3491                 :    : mShouldDraw(false)
    3492               0 :    , mResetCTM(false)
    3493               0 :   {}
    3494                 : 
    3495               0 :   SnappedImageDrawingParameters(const gfxMatrix& aUserSpaceToImageSpace,
    3496                 :                                 const gfxRect&   aFillRect,
    3497                 :                                 const nsIntRect& aSubimage,
    3498                 :                                 bool             aResetCTM)
    3499                 :    : mUserSpaceToImageSpace(aUserSpaceToImageSpace)
    3500                 :    , mFillRect(aFillRect)
    3501                 :    , mSubimage(aSubimage)
    3502                 :    , mShouldDraw(true)
    3503               0 :    , mResetCTM(aResetCTM)
    3504               0 :   {}
    3505                 : };
    3506                 : 
    3507                 : /**
    3508                 :  * Given a set of input parameters, compute certain output parameters
    3509                 :  * for drawing an image with the image snapping algorithm.
    3510                 :  * See https://wiki.mozilla.org/Gecko:Image_Snapping_and_Rendering
    3511                 :  *
    3512                 :  *  @see nsLayoutUtils::DrawImage() for the descriptions of input parameters
    3513                 :  */
    3514                 : static SnappedImageDrawingParameters
    3515               0 : ComputeSnappedImageDrawingParameters(gfxContext*     aCtx,
    3516                 :                                      PRInt32         aAppUnitsPerDevPixel,
    3517                 :                                      const nsRect    aDest,
    3518                 :                                      const nsRect    aFill,
    3519                 :                                      const nsPoint   aAnchor,
    3520                 :                                      const nsRect    aDirty,
    3521                 :                                      const nsIntSize aImageSize)
    3522                 : 
    3523                 : {
    3524               0 :   if (aDest.IsEmpty() || aFill.IsEmpty())
    3525               0 :     return SnappedImageDrawingParameters();
    3526                 : 
    3527                 :   gfxRect devPixelDest =
    3528               0 :     nsLayoutUtils::RectToGfxRect(aDest, aAppUnitsPerDevPixel);
    3529                 :   gfxRect devPixelFill =
    3530               0 :     nsLayoutUtils::RectToGfxRect(aFill, aAppUnitsPerDevPixel);
    3531                 :   gfxRect devPixelDirty =
    3532               0 :     nsLayoutUtils::RectToGfxRect(aDirty, aAppUnitsPerDevPixel);
    3533                 : 
    3534               0 :   bool ignoreScale = false;
    3535                 : #ifdef MOZ_GFX_OPTIMIZE_MOBILE
    3536                 :   ignoreScale = true;
    3537                 : #endif
    3538               0 :   gfxRect fill = devPixelFill;
    3539               0 :   bool didSnap = aCtx->UserToDevicePixelSnapped(fill, ignoreScale);
    3540                 : 
    3541               0 :   gfxSize imageSize(aImageSize.width, aImageSize.height);
    3542                 : 
    3543                 :   // Compute the set of pixels that would be sampled by an ideal rendering
    3544                 :   gfxPoint subimageTopLeft =
    3545               0 :     MapToFloatImagePixels(imageSize, devPixelDest, devPixelFill.TopLeft());
    3546                 :   gfxPoint subimageBottomRight =
    3547               0 :     MapToFloatImagePixels(imageSize, devPixelDest, devPixelFill.BottomRight());
    3548               0 :   nsIntRect intSubimage;
    3549                 :   intSubimage.MoveTo(NSToIntFloor(subimageTopLeft.x),
    3550               0 :                      NSToIntFloor(subimageTopLeft.y));
    3551               0 :   intSubimage.SizeTo(NSToIntCeil(subimageBottomRight.x) - intSubimage.x,
    3552               0 :                      NSToIntCeil(subimageBottomRight.y) - intSubimage.y);
    3553                 : 
    3554                 :   // Compute the anchor point and compute final fill rect.
    3555                 :   // This code assumes that pixel-based devices have one pixel per
    3556                 :   // device unit!
    3557                 :   gfxPoint anchorPoint(gfxFloat(aAnchor.x)/aAppUnitsPerDevPixel,
    3558               0 :                        gfxFloat(aAnchor.y)/aAppUnitsPerDevPixel);
    3559                 :   gfxPoint imageSpaceAnchorPoint =
    3560               0 :     MapToFloatImagePixels(imageSize, devPixelDest, anchorPoint);
    3561               0 :   gfxMatrix currentMatrix = aCtx->CurrentMatrix();
    3562                 : 
    3563               0 :   if (didSnap) {
    3564               0 :     NS_ASSERTION(!currentMatrix.HasNonAxisAlignedTransform(),
    3565                 :                  "How did we snap, then?");
    3566               0 :     imageSpaceAnchorPoint.Round();
    3567               0 :     anchorPoint = imageSpaceAnchorPoint;
    3568               0 :     anchorPoint = MapToFloatUserPixels(imageSize, devPixelDest, anchorPoint);
    3569               0 :     anchorPoint = currentMatrix.Transform(anchorPoint);
    3570               0 :     anchorPoint.Round();
    3571                 : 
    3572                 :     // This form of Transform is safe to call since non-axis-aligned
    3573                 :     // transforms wouldn't be snapped.
    3574               0 :     devPixelDirty = currentMatrix.Transform(devPixelDirty);
    3575                 :   }
    3576                 : 
    3577               0 :   gfxFloat scaleX = imageSize.width*aAppUnitsPerDevPixel/aDest.width;
    3578               0 :   gfxFloat scaleY = imageSize.height*aAppUnitsPerDevPixel/aDest.height;
    3579               0 :   if (didSnap) {
    3580                 :     // We'll reset aCTX to the identity matrix before drawing, so we need to
    3581                 :     // adjust our scales to match.
    3582               0 :     scaleX /= currentMatrix.xx;
    3583               0 :     scaleY /= currentMatrix.yy;
    3584                 :   }
    3585               0 :   gfxFloat translateX = imageSpaceAnchorPoint.x - anchorPoint.x*scaleX;
    3586               0 :   gfxFloat translateY = imageSpaceAnchorPoint.y - anchorPoint.y*scaleY;
    3587               0 :   gfxMatrix transform(scaleX, 0, 0, scaleY, translateX, translateY);
    3588                 : 
    3589               0 :   gfxRect finalFillRect = fill;
    3590                 :   // If the user-space-to-image-space transform is not a straight
    3591                 :   // translation by integers, then filtering will occur, and
    3592                 :   // restricting the fill rect to the dirty rect would change the values
    3593                 :   // computed for edge pixels, which we can't allow.
    3594                 :   // Also, if didSnap is false then rounding out 'devPixelDirty' might not
    3595                 :   // produce pixel-aligned coordinates, which would also break the values
    3596                 :   // computed for edge pixels.
    3597               0 :   if (didSnap && !transform.HasNonIntegerTranslation()) {
    3598               0 :     devPixelDirty.RoundOut();
    3599               0 :     finalFillRect = fill.Intersect(devPixelDirty);
    3600                 :   }
    3601               0 :   if (finalFillRect.IsEmpty())
    3602               0 :     return SnappedImageDrawingParameters();
    3603                 : 
    3604                 :   return SnappedImageDrawingParameters(transform, finalFillRect, intSubimage,
    3605               0 :                                        didSnap);
    3606                 : }
    3607                 : 
    3608                 : 
    3609                 : static nsresult
    3610               0 : DrawImageInternal(nsRenderingContext* aRenderingContext,
    3611                 :                   imgIContainer*       aImage,
    3612                 :                   GraphicsFilter       aGraphicsFilter,
    3613                 :                   const nsRect&        aDest,
    3614                 :                   const nsRect&        aFill,
    3615                 :                   const nsPoint&       aAnchor,
    3616                 :                   const nsRect&        aDirty,
    3617                 :                   const nsIntSize&     aImageSize,
    3618                 :                   PRUint32             aImageFlags)
    3619                 : {
    3620               0 :   PRInt32 appUnitsPerDevPixel = aRenderingContext->AppUnitsPerDevPixel();
    3621               0 :   gfxContext* ctx = aRenderingContext->ThebesContext();
    3622                 : 
    3623                 :   SnappedImageDrawingParameters drawingParams =
    3624                 :     ComputeSnappedImageDrawingParameters(ctx, appUnitsPerDevPixel, aDest, aFill,
    3625               0 :                                          aAnchor, aDirty, aImageSize);
    3626                 : 
    3627               0 :   if (!drawingParams.mShouldDraw)
    3628               0 :     return NS_OK;
    3629                 : 
    3630               0 :   gfxContextMatrixAutoSaveRestore saveMatrix(ctx);
    3631               0 :   if (drawingParams.mResetCTM) {
    3632               0 :     ctx->IdentityMatrix();
    3633                 :   }
    3634                 : 
    3635                 :   aImage->Draw(ctx, aGraphicsFilter, drawingParams.mUserSpaceToImageSpace,
    3636                 :                drawingParams.mFillRect, drawingParams.mSubimage, aImageSize,
    3637               0 :                aImageFlags);
    3638               0 :   return NS_OK;
    3639                 : }
    3640                 : 
    3641                 : /* static */ void
    3642               0 : nsLayoutUtils::DrawPixelSnapped(nsRenderingContext* aRenderingContext,
    3643                 :                                 gfxDrawable*         aDrawable,
    3644                 :                                 GraphicsFilter       aFilter,
    3645                 :                                 const nsRect&        aDest,
    3646                 :                                 const nsRect&        aFill,
    3647                 :                                 const nsPoint&       aAnchor,
    3648                 :                                 const nsRect&        aDirty)
    3649                 : {
    3650               0 :   PRInt32 appUnitsPerDevPixel = aRenderingContext->AppUnitsPerDevPixel();
    3651               0 :   gfxContext* ctx = aRenderingContext->ThebesContext();
    3652               0 :   gfxIntSize drawableSize = aDrawable->Size();
    3653               0 :   nsIntSize imageSize(drawableSize.width, drawableSize.height);
    3654                 : 
    3655                 :   SnappedImageDrawingParameters drawingParams =
    3656                 :     ComputeSnappedImageDrawingParameters(ctx, appUnitsPerDevPixel, aDest, aFill,
    3657               0 :                                          aAnchor, aDirty, imageSize);
    3658                 : 
    3659               0 :   if (!drawingParams.mShouldDraw)
    3660               0 :     return;
    3661                 : 
    3662               0 :   gfxContextMatrixAutoSaveRestore saveMatrix(ctx);
    3663               0 :   if (drawingParams.mResetCTM) {
    3664               0 :     ctx->IdentityMatrix();
    3665                 :   }
    3666                 : 
    3667                 :   gfxRect sourceRect =
    3668               0 :     drawingParams.mUserSpaceToImageSpace.Transform(drawingParams.mFillRect);
    3669               0 :   gfxRect imageRect(0, 0, imageSize.width, imageSize.height);
    3670                 :   gfxRect subimage(drawingParams.mSubimage.x, drawingParams.mSubimage.y,
    3671               0 :                    drawingParams.mSubimage.width, drawingParams.mSubimage.height);
    3672                 : 
    3673               0 :   NS_ASSERTION(!sourceRect.Intersect(subimage).IsEmpty(),
    3674                 :                "We must be allowed to sample *some* source pixels!");
    3675                 : 
    3676                 :   gfxUtils::DrawPixelSnapped(ctx, aDrawable,
    3677                 :                              drawingParams.mUserSpaceToImageSpace, subimage,
    3678                 :                              sourceRect, imageRect, drawingParams.mFillRect,
    3679               0 :                              gfxASurface::ImageFormatARGB32, aFilter);
    3680                 : }
    3681                 : 
    3682                 : /* static */ nsresult
    3683               0 : nsLayoutUtils::DrawSingleUnscaledImage(nsRenderingContext* aRenderingContext,
    3684                 :                                        imgIContainer*       aImage,
    3685                 :                                        GraphicsFilter       aGraphicsFilter,
    3686                 :                                        const nsPoint&       aDest,
    3687                 :                                        const nsRect*        aDirty,
    3688                 :                                        PRUint32             aImageFlags,
    3689                 :                                        const nsRect*        aSourceArea)
    3690                 : {
    3691               0 :   nsIntSize imageSize;
    3692               0 :   aImage->GetWidth(&imageSize.width);
    3693               0 :   aImage->GetHeight(&imageSize.height);
    3694               0 :   NS_ENSURE_TRUE(imageSize.width > 0 && imageSize.height > 0, NS_ERROR_FAILURE);
    3695                 : 
    3696               0 :   nscoord appUnitsPerCSSPixel = nsDeviceContext::AppUnitsPerCSSPixel();
    3697                 :   nsSize size(imageSize.width*appUnitsPerCSSPixel,
    3698               0 :               imageSize.height*appUnitsPerCSSPixel);
    3699                 : 
    3700               0 :   nsRect source;
    3701               0 :   if (aSourceArea) {
    3702               0 :     source = *aSourceArea;
    3703                 :   } else {
    3704               0 :     source.SizeTo(size);
    3705                 :   }
    3706                 : 
    3707               0 :   nsRect dest(aDest - source.TopLeft(), size);
    3708               0 :   nsRect fill(aDest, source.Size());
    3709                 :   // Ensure that only a single image tile is drawn. If aSourceArea extends
    3710                 :   // outside the image bounds, we want to honor the aSourceArea-to-aDest
    3711                 :   // translation but we don't want to actually tile the image.
    3712               0 :   fill.IntersectRect(fill, dest);
    3713                 :   return DrawImageInternal(aRenderingContext, aImage, aGraphicsFilter,
    3714                 :                            dest, fill, aDest, aDirty ? *aDirty : dest,
    3715               0 :                            imageSize, aImageFlags);
    3716                 : }
    3717                 : 
    3718                 : /* static */ nsresult
    3719               0 : nsLayoutUtils::DrawSingleImage(nsRenderingContext* aRenderingContext,
    3720                 :                                imgIContainer*       aImage,
    3721                 :                                GraphicsFilter       aGraphicsFilter,
    3722                 :                                const nsRect&        aDest,
    3723                 :                                const nsRect&        aDirty,
    3724                 :                                PRUint32             aImageFlags,
    3725                 :                                const nsRect*        aSourceArea)
    3726                 : {
    3727               0 :   nsIntSize imageSize;
    3728               0 :   if (aImage->GetType() == imgIContainer::TYPE_VECTOR) {
    3729               0 :     imageSize.width  = nsPresContext::AppUnitsToIntCSSPixels(aDest.width);
    3730               0 :     imageSize.height = nsPresContext::AppUnitsToIntCSSPixels(aDest.height);
    3731                 :   } else {
    3732               0 :     aImage->GetWidth(&imageSize.width);
    3733               0 :     aImage->GetHeight(&imageSize.height);
    3734                 :   }
    3735               0 :   NS_ENSURE_TRUE(imageSize.width > 0 && imageSize.height > 0, NS_ERROR_FAILURE);
    3736                 : 
    3737               0 :   nsRect source;
    3738               0 :   if (aSourceArea) {
    3739               0 :     source = *aSourceArea;
    3740                 :   } else {
    3741               0 :     nscoord appUnitsPerCSSPixel = nsDeviceContext::AppUnitsPerCSSPixel();
    3742                 :     source.SizeTo(imageSize.width*appUnitsPerCSSPixel,
    3743               0 :                   imageSize.height*appUnitsPerCSSPixel);
    3744                 :   }
    3745                 : 
    3746                 :   nsRect dest = nsLayoutUtils::GetWholeImageDestination(imageSize, source,
    3747               0 :                                                         aDest);
    3748                 :   // Ensure that only a single image tile is drawn. If aSourceArea extends
    3749                 :   // outside the image bounds, we want to honor the aSourceArea-to-aDest
    3750                 :   // transform but we don't want to actually tile the image.
    3751               0 :   nsRect fill;
    3752               0 :   fill.IntersectRect(aDest, dest);
    3753                 :   return DrawImageInternal(aRenderingContext, aImage, aGraphicsFilter, dest, fill,
    3754               0 :                            fill.TopLeft(), aDirty, imageSize, aImageFlags);
    3755                 : }
    3756                 : 
    3757                 : /* static */ void
    3758               0 : nsLayoutUtils::ComputeSizeForDrawing(imgIContainer *aImage,
    3759                 :                                      nsIntSize&     aImageSize, /*outparam*/
    3760                 :                                      nsSize&        aIntrinsicRatio, /*outparam*/
    3761                 :                                      bool&          aGotWidth,  /*outparam*/
    3762                 :                                      bool&          aGotHeight  /*outparam*/)
    3763                 : {
    3764               0 :   aGotWidth  = NS_SUCCEEDED(aImage->GetWidth(&aImageSize.width));
    3765               0 :   aGotHeight = NS_SUCCEEDED(aImage->GetHeight(&aImageSize.height));
    3766                 : 
    3767               0 :   if (aGotWidth && aGotHeight) {
    3768               0 :     aIntrinsicRatio = nsSize(aImageSize.width, aImageSize.height);
    3769               0 :     return;
    3770                 :   }
    3771                 : 
    3772                 :   // If we failed to get width or height, we either have a vector image and
    3773                 :   // should return its intrinsic ratio, or we hit an error (say, because the
    3774                 :   // image failed to load or couldn't be decoded) and should return zero size.
    3775               0 :   if (nsIFrame* rootFrame = aImage->GetRootLayoutFrame()) {
    3776               0 :     aIntrinsicRatio = rootFrame->GetIntrinsicRatio();
    3777                 :   } else {
    3778               0 :     aGotWidth = aGotHeight = true;
    3779               0 :     aImageSize = nsIntSize(0, 0);
    3780               0 :     aIntrinsicRatio = nsSize(0, 0);
    3781                 :   }
    3782                 : }
    3783                 : 
    3784                 : 
    3785                 : /* static */ nsresult
    3786               0 : nsLayoutUtils::DrawBackgroundImage(nsRenderingContext* aRenderingContext,
    3787                 :                                    imgIContainer*      aImage,
    3788                 :                                    const nsIntSize&    aImageSize,
    3789                 :                                    GraphicsFilter      aGraphicsFilter,
    3790                 :                                    const nsRect&       aDest,
    3791                 :                                    const nsRect&       aFill,
    3792                 :                                    const nsPoint&      aAnchor,
    3793                 :                                    const nsRect&       aDirty,
    3794                 :                                    PRUint32            aImageFlags)
    3795                 : {
    3796               0 :   SAMPLE_LABEL("layout", "nsLayoutUtils::DrawBackgroundImage");
    3797                 :   return DrawImageInternal(aRenderingContext, aImage, aGraphicsFilter,
    3798                 :                            aDest, aFill, aAnchor, aDirty,
    3799               0 :                            aImageSize, aImageFlags);
    3800                 : }
    3801                 : 
    3802                 : /* static */ nsresult
    3803               0 : nsLayoutUtils::DrawImage(nsRenderingContext* aRenderingContext,
    3804                 :                          imgIContainer*       aImage,
    3805                 :                          GraphicsFilter       aGraphicsFilter,
    3806                 :                          const nsRect&        aDest,
    3807                 :                          const nsRect&        aFill,
    3808                 :                          const nsPoint&       aAnchor,
    3809                 :                          const nsRect&        aDirty,
    3810                 :                          PRUint32             aImageFlags)
    3811                 : {
    3812               0 :   nsIntSize imageSize;
    3813               0 :   nsSize imageRatio;
    3814                 :   bool gotHeight, gotWidth;
    3815               0 :   ComputeSizeForDrawing(aImage, imageSize, imageRatio, gotWidth, gotHeight);
    3816                 : 
    3817                 :   // XXX Dimensionless images shouldn't fall back to filled-area size -- the
    3818                 :   //     caller should provide the image size, a la DrawBackgroundImage.
    3819               0 :   if (gotWidth != gotHeight) {
    3820               0 :     if (!gotWidth) {
    3821               0 :       if (imageRatio.height != 0) {
    3822                 :         imageSize.width =
    3823                 :           NSCoordSaturatingNonnegativeMultiply(imageSize.height,
    3824                 :                                                float(imageRatio.width) /
    3825               0 :                                                float(imageRatio.height));
    3826               0 :         gotWidth = true;
    3827                 :       }
    3828                 :     } else {
    3829               0 :       if (imageRatio.width != 0) {
    3830                 :         imageSize.height =
    3831                 :           NSCoordSaturatingNonnegativeMultiply(imageSize.width,
    3832                 :                                                float(imageRatio.height) /
    3833               0 :                                                float(imageRatio.width));
    3834               0 :         gotHeight = true;
    3835                 :       }
    3836                 :     }
    3837                 :   }
    3838                 : 
    3839               0 :   if (!gotWidth) {
    3840               0 :     imageSize.width = nsPresContext::AppUnitsToIntCSSPixels(aFill.width);
    3841                 :   }
    3842               0 :   if (!gotHeight) {
    3843               0 :     imageSize.height = nsPresContext::AppUnitsToIntCSSPixels(aFill.height);
    3844                 :   }
    3845                 : 
    3846                 :   return DrawImageInternal(aRenderingContext, aImage, aGraphicsFilter,
    3847                 :                            aDest, aFill, aAnchor, aDirty,
    3848               0 :                            imageSize, aImageFlags);
    3849                 : }
    3850                 : 
    3851                 : /* static */ nsRect
    3852               0 : nsLayoutUtils::GetWholeImageDestination(const nsIntSize& aWholeImageSize,
    3853                 :                                         const nsRect& aImageSourceArea,
    3854                 :                                         const nsRect& aDestArea)
    3855                 : {
    3856               0 :   double scaleX = double(aDestArea.width)/aImageSourceArea.width;
    3857               0 :   double scaleY = double(aDestArea.height)/aImageSourceArea.height;
    3858               0 :   nscoord destOffsetX = NSToCoordRound(aImageSourceArea.x*scaleX);
    3859               0 :   nscoord destOffsetY = NSToCoordRound(aImageSourceArea.y*scaleY);
    3860               0 :   nscoord appUnitsPerCSSPixel = nsDeviceContext::AppUnitsPerCSSPixel();
    3861               0 :   nscoord wholeSizeX = NSToCoordRound(aWholeImageSize.width*appUnitsPerCSSPixel*scaleX);
    3862               0 :   nscoord wholeSizeY = NSToCoordRound(aWholeImageSize.height*appUnitsPerCSSPixel*scaleY);
    3863                 :   return nsRect(aDestArea.TopLeft() - nsPoint(destOffsetX, destOffsetY),
    3864               0 :                 nsSize(wholeSizeX, wholeSizeY));
    3865                 : }
    3866                 : 
    3867               0 : static bool NonZeroStyleCoord(const nsStyleCoord& aCoord)
    3868                 : {
    3869               0 :   if (aCoord.IsCoordPercentCalcUnit()) {
    3870                 :     // Since negative results are clamped to 0, check > 0.
    3871               0 :     return nsRuleNode::ComputeCoordPercentCalc(aCoord, nscoord_MAX) > 0 ||
    3872               0 :            nsRuleNode::ComputeCoordPercentCalc(aCoord, 0) > 0;
    3873                 :   }
    3874                 : 
    3875               0 :   return true;
    3876                 : }
    3877                 : 
    3878                 : /* static */ bool
    3879               0 : nsLayoutUtils::HasNonZeroCorner(const nsStyleCorners& aCorners)
    3880                 : {
    3881               0 :   NS_FOR_CSS_HALF_CORNERS(corner) {
    3882               0 :     if (NonZeroStyleCoord(aCorners.Get(corner)))
    3883               0 :       return true;
    3884                 :   }
    3885               0 :   return false;
    3886                 : }
    3887                 : 
    3888                 : // aCorner is a "full corner" value, i.e. NS_CORNER_TOP_LEFT etc
    3889               0 : static bool IsCornerAdjacentToSide(PRUint8 aCorner, mozilla::css::Side aSide)
    3890                 : {
    3891                 :   PR_STATIC_ASSERT((int)NS_SIDE_TOP == NS_CORNER_TOP_LEFT);
    3892                 :   PR_STATIC_ASSERT((int)NS_SIDE_RIGHT == NS_CORNER_TOP_RIGHT);
    3893                 :   PR_STATIC_ASSERT((int)NS_SIDE_BOTTOM == NS_CORNER_BOTTOM_RIGHT);
    3894                 :   PR_STATIC_ASSERT((int)NS_SIDE_LEFT == NS_CORNER_BOTTOM_LEFT);
    3895                 :   PR_STATIC_ASSERT((int)NS_SIDE_TOP == ((NS_CORNER_TOP_RIGHT - 1)&3));
    3896                 :   PR_STATIC_ASSERT((int)NS_SIDE_RIGHT == ((NS_CORNER_BOTTOM_RIGHT - 1)&3));
    3897                 :   PR_STATIC_ASSERT((int)NS_SIDE_BOTTOM == ((NS_CORNER_BOTTOM_LEFT - 1)&3));
    3898                 :   PR_STATIC_ASSERT((int)NS_SIDE_LEFT == ((NS_CORNER_TOP_LEFT - 1)&3));
    3899                 : 
    3900               0 :   return aSide == aCorner || aSide == ((aCorner - 1)&3);
    3901                 : }
    3902                 : 
    3903                 : /* static */ bool
    3904               0 : nsLayoutUtils::HasNonZeroCornerOnSide(const nsStyleCorners& aCorners,
    3905                 :                                       mozilla::css::Side aSide)
    3906                 : {
    3907                 :   PR_STATIC_ASSERT(NS_CORNER_TOP_LEFT_X/2 == NS_CORNER_TOP_LEFT);
    3908                 :   PR_STATIC_ASSERT(NS_CORNER_TOP_LEFT_Y/2 == NS_CORNER_TOP_LEFT);
    3909                 :   PR_STATIC_ASSERT(NS_CORNER_TOP_RIGHT_X/2 == NS_CORNER_TOP_RIGHT);
    3910                 :   PR_STATIC_ASSERT(NS_CORNER_TOP_RIGHT_Y/2 == NS_CORNER_TOP_RIGHT);
    3911                 :   PR_STATIC_ASSERT(NS_CORNER_BOTTOM_RIGHT_X/2 == NS_CORNER_BOTTOM_RIGHT);
    3912                 :   PR_STATIC_ASSERT(NS_CORNER_BOTTOM_RIGHT_Y/2 == NS_CORNER_BOTTOM_RIGHT);
    3913                 :   PR_STATIC_ASSERT(NS_CORNER_BOTTOM_LEFT_X/2 == NS_CORNER_BOTTOM_LEFT);
    3914                 :   PR_STATIC_ASSERT(NS_CORNER_BOTTOM_LEFT_Y/2 == NS_CORNER_BOTTOM_LEFT);
    3915                 : 
    3916               0 :   NS_FOR_CSS_HALF_CORNERS(corner) {
    3917                 :     // corner is a "half corner" value, so dividing by two gives us a
    3918                 :     // "full corner" value.
    3919               0 :     if (NonZeroStyleCoord(aCorners.Get(corner)) &&
    3920               0 :         IsCornerAdjacentToSide(corner/2, aSide))
    3921               0 :       return true;
    3922                 :   }
    3923               0 :   return false;
    3924                 : }
    3925                 : 
    3926                 : /* static */ nsTransparencyMode
    3927               0 : nsLayoutUtils::GetFrameTransparency(nsIFrame* aBackgroundFrame,
    3928                 :                                     nsIFrame* aCSSRootFrame) {
    3929               0 :   if (aCSSRootFrame->GetStyleContext()->GetStyleDisplay()->mOpacity < 1.0f)
    3930               0 :     return eTransparencyTransparent;
    3931                 : 
    3932               0 :   if (HasNonZeroCorner(aCSSRootFrame->GetStyleContext()->GetStyleBorder()->mBorderRadius))
    3933               0 :     return eTransparencyTransparent;
    3934                 : 
    3935               0 :   if (aCSSRootFrame->GetStyleDisplay()->mAppearance == NS_THEME_WIN_GLASS)
    3936               0 :     return eTransparencyGlass;
    3937                 : 
    3938               0 :   if (aCSSRootFrame->GetStyleDisplay()->mAppearance == NS_THEME_WIN_BORDERLESS_GLASS)
    3939               0 :     return eTransparencyBorderlessGlass;
    3940                 : 
    3941                 :   nsITheme::Transparency transparency;
    3942               0 :   if (aCSSRootFrame->IsThemed(&transparency))
    3943                 :     return transparency == nsITheme::eTransparent
    3944                 :          ? eTransparencyTransparent
    3945               0 :          : eTransparencyOpaque;
    3946                 : 
    3947                 :   // We need an uninitialized window to be treated as opaque because
    3948                 :   // doing otherwise breaks window display effects on some platforms,
    3949                 :   // specifically Vista. (bug 450322)
    3950               0 :   if (aBackgroundFrame->GetType() == nsGkAtoms::viewportFrame &&
    3951               0 :       !aBackgroundFrame->GetFirstPrincipalChild()) {
    3952               0 :     return eTransparencyOpaque;
    3953                 :   }
    3954                 : 
    3955                 :   nsStyleContext* bgSC;
    3956               0 :   if (!nsCSSRendering::FindBackground(aBackgroundFrame->PresContext(),
    3957               0 :                                       aBackgroundFrame, &bgSC)) {
    3958               0 :     return eTransparencyTransparent;
    3959                 :   }
    3960               0 :   const nsStyleBackground* bg = bgSC->GetStyleBackground();
    3961               0 :   if (NS_GET_A(bg->mBackgroundColor) < 255 ||
    3962                 :       // bottom layer's clip is used for the color
    3963               0 :       bg->BottomLayer().mClip != NS_STYLE_BG_CLIP_BORDER)
    3964               0 :     return eTransparencyTransparent;
    3965               0 :   return eTransparencyOpaque;
    3966                 : }
    3967                 : 
    3968               0 : static bool IsPopupFrame(nsIFrame* aFrame)
    3969                 : {
    3970                 :   // aFrame is a popup it's the list control frame dropdown for a combobox.
    3971               0 :   nsIAtom* frameType = aFrame->GetType();
    3972               0 :   if (frameType == nsGkAtoms::listControlFrame) {
    3973               0 :     nsListControlFrame* lcf = static_cast<nsListControlFrame*>(aFrame);
    3974               0 :     return lcf->IsInDropDownMode();
    3975                 :   }
    3976                 : 
    3977                 :   // ... or if it's a XUL menupopup frame.
    3978               0 :   return frameType == nsGkAtoms::menuPopupFrame;
    3979                 : }
    3980                 : 
    3981                 : /* static */ bool
    3982               0 : nsLayoutUtils::IsPopup(nsIFrame* aFrame)
    3983                 : {
    3984                 :   // Optimization: the frame can't possibly be a popup if it has no view.
    3985               0 :   if (!aFrame->HasView()) {
    3986               0 :     NS_ASSERTION(!IsPopupFrame(aFrame), "popup frame must have a view");
    3987               0 :     return false;
    3988                 :   }
    3989               0 :   return IsPopupFrame(aFrame);
    3990                 : }
    3991                 : 
    3992                 : /* static */ nsIFrame*
    3993               0 : nsLayoutUtils::GetDisplayRootFrame(nsIFrame* aFrame)
    3994                 : {
    3995               0 :   nsIFrame* f = aFrame;
    3996               0 :   for (;;) {
    3997               0 :     if (IsPopup(f))
    3998               0 :       return f;
    3999               0 :     nsIFrame* parent = GetCrossDocParentFrame(f);
    4000               0 :     if (!parent)
    4001               0 :       return f;
    4002               0 :     f = parent;
    4003                 :   }
    4004                 : }
    4005                 : 
    4006                 : static bool
    4007               0 : IsNonzeroCoord(const nsStyleCoord& aCoord)
    4008                 : {
    4009               0 :   if (eStyleUnit_Coord == aCoord.GetUnit())
    4010               0 :     return aCoord.GetCoordValue() != 0;
    4011               0 :   return false;
    4012                 : }
    4013                 : 
    4014                 : /* static */ PRUint32
    4015               0 : nsLayoutUtils::GetTextRunFlagsForStyle(nsStyleContext* aStyleContext,
    4016                 :                                        const nsStyleText* aStyleText,
    4017                 :                                        const nsStyleFont* aStyleFont)
    4018                 : {
    4019               0 :   PRUint32 result = 0;
    4020               0 :   if (IsNonzeroCoord(aStyleText->mLetterSpacing)) {
    4021               0 :     result |= gfxTextRunFactory::TEXT_DISABLE_OPTIONAL_LIGATURES;
    4022                 :   }
    4023               0 :   switch (aStyleContext->GetStyleSVG()->mTextRendering) {
    4024                 :   case NS_STYLE_TEXT_RENDERING_OPTIMIZESPEED:
    4025               0 :     result |= gfxTextRunFactory::TEXT_OPTIMIZE_SPEED;
    4026               0 :     break;
    4027                 :   case NS_STYLE_TEXT_RENDERING_AUTO:
    4028               0 :     if (aStyleFont->mFont.size <
    4029               0 :         aStyleContext->PresContext()->GetAutoQualityMinFontSize()) {
    4030               0 :       result |= gfxTextRunFactory::TEXT_OPTIMIZE_SPEED;
    4031                 :     }
    4032               0 :     break;
    4033                 :   default:
    4034               0 :     break;
    4035                 :   }
    4036               0 :   return result;
    4037                 : }
    4038                 : 
    4039                 : /* static */ void
    4040               0 : nsLayoutUtils::GetRectDifferenceStrips(const nsRect& aR1, const nsRect& aR2,
    4041                 :                                        nsRect* aHStrip, nsRect* aVStrip) {
    4042               0 :   NS_ASSERTION(aR1.TopLeft() == aR2.TopLeft(),
    4043                 :                "expected rects at the same position");
    4044               0 :   nsRect unionRect(aR1.x, aR1.y, NS_MAX(aR1.width, aR2.width),
    4045               0 :                    NS_MAX(aR1.height, aR2.height));
    4046               0 :   nscoord VStripStart = NS_MIN(aR1.width, aR2.width);
    4047               0 :   nscoord HStripStart = NS_MIN(aR1.height, aR2.height);
    4048               0 :   *aVStrip = unionRect;
    4049               0 :   aVStrip->x += VStripStart;
    4050               0 :   aVStrip->width -= VStripStart;
    4051               0 :   *aHStrip = unionRect;
    4052               0 :   aHStrip->y += HStripStart;
    4053               0 :   aHStrip->height -= HStripStart;
    4054               0 : }
    4055                 : 
    4056                 : nsDeviceContext*
    4057               0 : nsLayoutUtils::GetDeviceContextForScreenInfo(nsIDocShell* aDocShell)
    4058                 : {
    4059               0 :   nsCOMPtr<nsIDocShell> docShell = aDocShell;
    4060               0 :   while (docShell) {
    4061                 :     // Now make sure our size is up to date.  That will mean that the device
    4062                 :     // context does the right thing on multi-monitor systems when we return it to
    4063                 :     // the caller.  It will also make sure that our prescontext has been created,
    4064                 :     // if we're supposed to have one.
    4065               0 :     nsCOMPtr<nsPIDOMWindow> win = do_GetInterface(docShell);
    4066               0 :     if (!win) {
    4067                 :       // No reason to go on
    4068               0 :       return nsnull;
    4069                 :     }
    4070                 : 
    4071               0 :     win->EnsureSizeUpToDate();
    4072                 : 
    4073               0 :     nsRefPtr<nsPresContext> presContext;
    4074               0 :     docShell->GetPresContext(getter_AddRefs(presContext));
    4075               0 :     if (presContext) {
    4076               0 :       nsDeviceContext* context = presContext->DeviceContext();
    4077               0 :       if (context) {
    4078               0 :         return context;
    4079                 :       }
    4080                 :     }
    4081                 : 
    4082               0 :     nsCOMPtr<nsIDocShellTreeItem> curItem = do_QueryInterface(docShell);
    4083               0 :     nsCOMPtr<nsIDocShellTreeItem> parentItem;
    4084               0 :     curItem->GetParent(getter_AddRefs(parentItem));
    4085               0 :     docShell = do_QueryInterface(parentItem);
    4086                 :   }
    4087                 : 
    4088               0 :   return nsnull;
    4089                 : }
    4090                 : 
    4091                 : /* static */ bool
    4092               0 : nsLayoutUtils::IsReallyFixedPos(nsIFrame* aFrame)
    4093                 : {
    4094               0 :   NS_PRECONDITION(aFrame->GetParent(),
    4095                 :                   "IsReallyFixedPos called on frame not in tree");
    4096               0 :   NS_PRECONDITION(aFrame->GetStyleDisplay()->mPosition ==
    4097                 :                     NS_STYLE_POSITION_FIXED,
    4098                 :                   "IsReallyFixedPos called on non-'position:fixed' frame");
    4099                 : 
    4100               0 :   nsIAtom *parentType = aFrame->GetParent()->GetType();
    4101                 :   return parentType == nsGkAtoms::viewportFrame ||
    4102               0 :          parentType == nsGkAtoms::pageContentFrame;
    4103                 : }
    4104                 : 
    4105                 : nsLayoutUtils::SurfaceFromElementResult
    4106               0 : nsLayoutUtils::SurfaceFromElement(dom::Element* aElement,
    4107                 :                                   PRUint32 aSurfaceFlags)
    4108                 : {
    4109               0 :   SurfaceFromElementResult result;
    4110                 :   nsresult rv;
    4111                 : 
    4112               0 :   bool forceCopy = (aSurfaceFlags & SFE_WANT_NEW_SURFACE) != 0;
    4113               0 :   bool wantImageSurface = (aSurfaceFlags & SFE_WANT_IMAGE_SURFACE) != 0;
    4114                 : 
    4115               0 :   if (aSurfaceFlags & SFE_NO_PREMULTIPLY_ALPHA) {
    4116               0 :     forceCopy = true;
    4117               0 :     wantImageSurface = true;
    4118                 :   }
    4119                 : 
    4120                 :   // If it's a <canvas>, we may be able to just grab its internal surface
    4121               0 :   if (nsHTMLCanvasElement* canvas = nsHTMLCanvasElement::FromContent(aElement)) {
    4122               0 :     gfxIntSize size = canvas->GetSize();
    4123                 : 
    4124               0 :     nsRefPtr<gfxASurface> surf;
    4125                 : 
    4126               0 :     if (!forceCopy && canvas->CountContexts() == 1) {
    4127               0 :       nsICanvasRenderingContextInternal *srcCanvas = canvas->GetContextAtIndex(0);
    4128               0 :       rv = srcCanvas->GetThebesSurface(getter_AddRefs(surf));
    4129                 : 
    4130               0 :       if (NS_FAILED(rv))
    4131               0 :         surf = nsnull;
    4132                 :     }
    4133                 : 
    4134               0 :     if (surf && wantImageSurface && surf->GetType() != gfxASurface::SurfaceTypeImage)
    4135               0 :       surf = nsnull;
    4136                 : 
    4137               0 :     if (!surf) {
    4138               0 :       if (wantImageSurface) {
    4139               0 :         surf = new gfxImageSurface(size, gfxASurface::ImageFormatARGB32);
    4140                 :       } else {
    4141               0 :         surf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(size, gfxASurface::CONTENT_COLOR_ALPHA);
    4142                 :       }
    4143                 : 
    4144               0 :       nsRefPtr<gfxContext> ctx = new gfxContext(surf);
    4145                 :       // XXX shouldn't use the external interface, but maybe we can layerify this
    4146               0 :       rv = canvas->RenderContextsExternal(ctx, gfxPattern::FILTER_NEAREST);
    4147               0 :       if (NS_FAILED(rv))
    4148                 :         return result;
    4149                 :     }
    4150                 : 
    4151                 :     // Ensure that any future changes to the canvas trigger proper invalidation,
    4152                 :     // in case this is being used by -moz-element()
    4153               0 :     canvas->MarkContextClean();
    4154                 : 
    4155               0 :     if (aSurfaceFlags & SFE_NO_PREMULTIPLY_ALPHA) {
    4156                 :       // we can modify this surface since we force a copy above when
    4157                 :       // when NO_PREMULTIPLY_ALPHA is set
    4158               0 :       gfxUtils::UnpremultiplyImageSurface(static_cast<gfxImageSurface*>(surf.get()));
    4159                 :     }
    4160                 : 
    4161               0 :     result.mSurface = surf;
    4162               0 :     result.mSize = size;
    4163               0 :     result.mPrincipal = aElement->NodePrincipal();
    4164               0 :     result.mIsWriteOnly = canvas->IsWriteOnly();
    4165                 : 
    4166                 :     return result;
    4167                 :   }
    4168                 : 
    4169                 : #ifdef MOZ_MEDIA
    4170                 :   // Maybe it's <video>?
    4171               0 :   if (nsHTMLVideoElement* video = nsHTMLVideoElement::FromContent(aElement)) {
    4172                 :     PRUint16 readyState;
    4173               0 :     if (NS_SUCCEEDED(video->GetReadyState(&readyState)) &&
    4174                 :         (readyState == nsIDOMHTMLMediaElement::HAVE_NOTHING ||
    4175                 :          readyState == nsIDOMHTMLMediaElement::HAVE_METADATA)) {
    4176               0 :       result.mIsStillLoading = true;
    4177               0 :       return result;
    4178                 :     }
    4179                 : 
    4180                 :     // If it doesn't have a principal, just bail
    4181               0 :     nsCOMPtr<nsIPrincipal> principal = video->GetCurrentPrincipal();
    4182               0 :     if (!principal)
    4183                 :       return result;
    4184                 : 
    4185               0 :     ImageContainer *container = video->GetImageContainer();
    4186               0 :     if (!container)
    4187                 :       return result;
    4188                 : 
    4189               0 :     gfxIntSize size;
    4190               0 :     nsRefPtr<gfxASurface> surf = container->GetCurrentAsSurface(&size);
    4191               0 :     if (!surf)
    4192                 :       return result;
    4193                 : 
    4194               0 :     if (wantImageSurface && surf->GetType() != gfxASurface::SurfaceTypeImage) {
    4195                 :       nsRefPtr<gfxImageSurface> imgSurf =
    4196               0 :         new gfxImageSurface(size, gfxASurface::ImageFormatARGB32);
    4197                 : 
    4198               0 :       nsRefPtr<gfxContext> ctx = new gfxContext(imgSurf);
    4199               0 :       ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
    4200               0 :       ctx->DrawSurface(surf, size);
    4201               0 :       surf = imgSurf;
    4202                 :     }
    4203                 : 
    4204               0 :     result.mCORSUsed = video->GetCORSMode() != CORS_NONE;
    4205               0 :     result.mSurface = surf;
    4206               0 :     result.mSize = size;
    4207               0 :     result.mPrincipal = principal.forget();
    4208               0 :     result.mIsWriteOnly = false;
    4209                 : 
    4210                 :     return result;
    4211                 :   }
    4212                 : #endif
    4213                 : 
    4214                 :   // Finally, check if it's a normal image
    4215               0 :   nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(aElement);
    4216                 : 
    4217               0 :   if (!imageLoader)
    4218                 :     return result;
    4219                 : 
    4220                 :   // Push a null JSContext on the stack so that code that runs within
    4221                 :   // the below code doesn't think it's being called by JS. See bug
    4222                 :   // 604262.
    4223               0 :   nsCxPusher pusher;
    4224               0 :   pusher.PushNull();
    4225                 : 
    4226               0 :   nsCOMPtr<imgIRequest> imgRequest;
    4227               0 :   rv = imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
    4228               0 :                                getter_AddRefs(imgRequest));
    4229               0 :   if (NS_FAILED(rv) || !imgRequest)
    4230                 :     return result;
    4231                 : 
    4232                 :   PRUint32 status;
    4233               0 :   imgRequest->GetImageStatus(&status);
    4234               0 :   if ((status & imgIRequest::STATUS_LOAD_COMPLETE) == 0) {
    4235                 :     // Spec says to use GetComplete, but that only works on
    4236                 :     // nsIDOMHTMLImageElement, and we support all sorts of other stuff
    4237                 :     // here.  Do this for now pending spec clarification.
    4238               0 :     result.mIsStillLoading = (status & imgIRequest::STATUS_ERROR) == 0;
    4239                 :     return result;
    4240                 :   }
    4241                 : 
    4242               0 :   nsCOMPtr<nsIPrincipal> principal;
    4243               0 :   rv = imgRequest->GetImagePrincipal(getter_AddRefs(principal));
    4244               0 :   if (NS_FAILED(rv) || !principal)
    4245                 :     return result;
    4246                 : 
    4247               0 :   nsCOMPtr<imgIContainer> imgContainer;
    4248               0 :   rv = imgRequest->GetImage(getter_AddRefs(imgContainer));
    4249               0 :   if (NS_FAILED(rv) || !imgContainer)
    4250                 :     return result;
    4251                 : 
    4252                 :   PRUint32 whichFrame = (aSurfaceFlags & SFE_WANT_FIRST_FRAME)
    4253                 :                         ? (PRUint32) imgIContainer::FRAME_FIRST
    4254               0 :                         : (PRUint32) imgIContainer::FRAME_CURRENT;
    4255               0 :   PRUint32 frameFlags = imgIContainer::FLAG_SYNC_DECODE;
    4256               0 :   if (aSurfaceFlags & SFE_NO_COLORSPACE_CONVERSION)
    4257               0 :     frameFlags |= imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION;
    4258               0 :   if (aSurfaceFlags & SFE_NO_PREMULTIPLY_ALPHA)
    4259               0 :     frameFlags |= imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
    4260               0 :   nsRefPtr<gfxASurface> framesurf;
    4261               0 :   rv = imgContainer->GetFrame(whichFrame,
    4262                 :                               frameFlags,
    4263               0 :                               getter_AddRefs(framesurf));
    4264               0 :   if (NS_FAILED(rv))
    4265                 :     return result;
    4266                 : 
    4267                 :   PRInt32 imgWidth, imgHeight;
    4268               0 :   rv = imgContainer->GetWidth(&imgWidth);
    4269               0 :   rv |= imgContainer->GetHeight(&imgHeight);
    4270               0 :   if (NS_FAILED(rv))
    4271                 :     return result;
    4272                 : 
    4273               0 :   if (wantImageSurface && framesurf->GetType() != gfxASurface::SurfaceTypeImage) {
    4274               0 :     forceCopy = true;
    4275                 :   }
    4276                 : 
    4277               0 :   nsRefPtr<gfxASurface> gfxsurf = framesurf;
    4278               0 :   if (forceCopy) {
    4279               0 :     if (wantImageSurface) {
    4280               0 :       gfxsurf = new gfxImageSurface (gfxIntSize(imgWidth, imgHeight), gfxASurface::ImageFormatARGB32);
    4281                 :     } else {
    4282               0 :       gfxsurf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(imgWidth, imgHeight),
    4283               0 :                                                                    gfxASurface::CONTENT_COLOR_ALPHA);
    4284                 :     }
    4285                 : 
    4286               0 :     nsRefPtr<gfxContext> ctx = new gfxContext(gfxsurf);
    4287                 : 
    4288               0 :     ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
    4289               0 :     ctx->SetSource(framesurf);
    4290               0 :     ctx->Paint();
    4291                 :   }
    4292                 : 
    4293                 :   PRInt32 corsmode;
    4294               0 :   if (NS_SUCCEEDED(imgRequest->GetCORSMode(&corsmode))) {
    4295               0 :     result.mCORSUsed = (corsmode != imgIRequest::CORS_NONE);
    4296                 :   }
    4297                 : 
    4298               0 :   result.mSurface = gfxsurf;
    4299               0 :   result.mSize = gfxIntSize(imgWidth, imgHeight);
    4300               0 :   result.mPrincipal = principal.forget();
    4301                 :   // no images, including SVG images, can load content from another domain.
    4302               0 :   result.mIsWriteOnly = false;
    4303               0 :   result.mImageRequest = imgRequest.forget();
    4304                 : 
    4305                 :   return result;
    4306                 : }
    4307                 : 
    4308                 : /* static */
    4309                 : nsIContent*
    4310               0 : nsLayoutUtils::GetEditableRootContentByContentEditable(nsIDocument* aDocument)
    4311                 : {
    4312                 :   // If the document is in designMode we should return NULL.
    4313               0 :   if (!aDocument || aDocument->HasFlag(NODE_IS_EDITABLE)) {
    4314               0 :     return nsnull;
    4315                 :   }
    4316                 : 
    4317                 :   // contenteditable only works with HTML document.
    4318                 :   // Note: Use nsIDOMHTMLDocument rather than nsIHTMLDocument for getting the
    4319                 :   //       body node because nsIDOMHTMLDocument::GetBody() does something
    4320                 :   //       additional work for some cases and nsEditor uses them.
    4321               0 :   nsCOMPtr<nsIDOMHTMLDocument> domHTMLDoc = do_QueryInterface(aDocument);
    4322               0 :   if (!domHTMLDoc) {
    4323               0 :     return nsnull;
    4324                 :   }
    4325                 : 
    4326               0 :   Element* rootElement = aDocument->GetRootElement();
    4327               0 :   if (rootElement && rootElement->IsEditable()) {
    4328               0 :     return rootElement;
    4329                 :   }
    4330                 : 
    4331                 :   // If there are no editable root element, check its <body> element.
    4332                 :   // Note that the body element could be <frameset> element.
    4333               0 :   nsCOMPtr<nsIDOMHTMLElement> body;
    4334               0 :   nsresult rv = domHTMLDoc->GetBody(getter_AddRefs(body));
    4335               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(body);
    4336               0 :   if (NS_SUCCEEDED(rv) && content && content->IsEditable()) {
    4337               0 :     return content;
    4338                 :   }
    4339               0 :   return nsnull;
    4340                 : }
    4341                 : 
    4342                 : #ifdef DEBUG
    4343                 : /* static */ void
    4344               0 : nsLayoutUtils::AssertNoDuplicateContinuations(nsIFrame* aContainer,
    4345                 :                                               const nsFrameList& aFrameList)
    4346                 : {
    4347               0 :   for (nsIFrame* f = aFrameList.FirstChild(); f ; f = f->GetNextSibling()) {
    4348                 :     // Check only later continuations of f; we deal with checking the
    4349                 :     // earlier continuations when we hit those earlier continuations in
    4350                 :     // the frame list.
    4351               0 :     for (nsIFrame *c = f; (c = c->GetNextInFlow());) {
    4352               0 :       NS_ASSERTION(c->GetParent() != aContainer ||
    4353                 :                    !aFrameList.ContainsFrame(c),
    4354                 :                    "Two continuations of the same frame in the same "
    4355                 :                    "frame list");
    4356                 :     }
    4357                 :   }
    4358               0 : }
    4359                 : 
    4360                 : // Is one of aFrame's ancestors a letter frame?
    4361                 : static bool
    4362               0 : IsInLetterFrame(nsIFrame *aFrame)
    4363                 : {
    4364               0 :   for (nsIFrame *f = aFrame->GetParent(); f; f = f->GetParent()) {
    4365               0 :     if (f->GetType() == nsGkAtoms::letterFrame) {
    4366               0 :       return true;
    4367                 :     }
    4368                 :   }
    4369               0 :   return false;
    4370                 : }
    4371                 : 
    4372                 : /* static */ void
    4373               0 : nsLayoutUtils::AssertTreeOnlyEmptyNextInFlows(nsIFrame *aSubtreeRoot)
    4374                 : {
    4375               0 :   NS_ASSERTION(aSubtreeRoot->GetPrevInFlow(),
    4376                 :                "frame tree not empty, but caller reported complete status");
    4377                 : 
    4378                 :   // Also assert that text frames map no text.
    4379                 :   PRInt32 start, end;
    4380               0 :   nsresult rv = aSubtreeRoot->GetOffsets(start, end);
    4381               0 :   NS_ASSERTION(NS_SUCCEEDED(rv), "GetOffsets failed");
    4382                 :   // In some cases involving :first-letter, we'll partially unlink a
    4383                 :   // continuation in the middle of a continuation chain from its
    4384                 :   // previous and next continuations before destroying it, presumably so
    4385                 :   // that we don't also destroy the later continuations.  Once we've
    4386                 :   // done this, GetOffsets returns incorrect values.
    4387                 :   // For examples, see list of tests in
    4388                 :   // https://bugzilla.mozilla.org/show_bug.cgi?id=619021#c29
    4389               0 :   NS_ASSERTION(start == end || IsInLetterFrame(aSubtreeRoot),
    4390                 :                "frame tree not empty, but caller reported complete status");
    4391                 : 
    4392               0 :   nsIFrame::ChildListIterator lists(aSubtreeRoot);
    4393               0 :   for (; !lists.IsDone(); lists.Next()) {
    4394               0 :     nsFrameList::Enumerator childFrames(lists.CurrentList());
    4395               0 :     for (; !childFrames.AtEnd(); childFrames.Next()) {
    4396               0 :       nsLayoutUtils::AssertTreeOnlyEmptyNextInFlows(childFrames.get());
    4397                 :     }
    4398                 :   }
    4399               0 : }
    4400                 : #endif
    4401                 : 
    4402                 : /* static */
    4403                 : nsresult
    4404               0 : nsLayoutUtils::GetFontFacesForFrames(nsIFrame* aFrame,
    4405                 :                                      nsFontFaceList* aFontFaceList)
    4406                 : {
    4407               0 :   NS_PRECONDITION(aFrame, "NULL frame pointer");
    4408                 : 
    4409               0 :   if (aFrame->GetType() == nsGkAtoms::textFrame) {
    4410                 :     return GetFontFacesForText(aFrame, 0, PR_INT32_MAX, false,
    4411               0 :                                aFontFaceList);
    4412                 :   }
    4413                 : 
    4414               0 :   while (aFrame) {
    4415                 :     nsIFrame::ChildListID childLists[] = { nsIFrame::kPrincipalList,
    4416               0 :                                            nsIFrame::kPopupList };
    4417               0 :     for (size_t i = 0; i < ArrayLength(childLists); ++i) {
    4418               0 :       nsFrameList children(aFrame->GetChildList(childLists[i]));
    4419               0 :       for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) {
    4420               0 :         nsIFrame* child = e.get();
    4421               0 :         if (child->GetPrevContinuation()) {
    4422               0 :           continue;
    4423                 :         }
    4424               0 :         child = nsPlaceholderFrame::GetRealFrameFor(child);
    4425               0 :         nsresult rv = GetFontFacesForFrames(child, aFontFaceList);
    4426               0 :         NS_ENSURE_SUCCESS(rv, rv);
    4427                 :       }
    4428                 :     }
    4429               0 :     aFrame = GetNextContinuationOrSpecialSibling(aFrame);
    4430                 :   }
    4431                 : 
    4432               0 :   return NS_OK;
    4433                 : }
    4434                 : 
    4435                 : /* static */
    4436                 : nsresult
    4437               0 : nsLayoutUtils::GetFontFacesForText(nsIFrame* aFrame,
    4438                 :                                    PRInt32 aStartOffset, PRInt32 aEndOffset,
    4439                 :                                    bool aFollowContinuations,
    4440                 :                                    nsFontFaceList* aFontFaceList)
    4441                 : {
    4442               0 :   NS_PRECONDITION(aFrame, "NULL frame pointer");
    4443                 : 
    4444               0 :   if (aFrame->GetType() != nsGkAtoms::textFrame) {
    4445               0 :     return NS_OK;
    4446                 :   }
    4447                 : 
    4448               0 :   nsTextFrame* curr = static_cast<nsTextFrame*>(aFrame);
    4449               0 :   do {
    4450               0 :     PRInt32 fstart = NS_MAX(curr->GetContentOffset(), aStartOffset);
    4451               0 :     PRInt32 fend = NS_MIN(curr->GetContentEnd(), aEndOffset);
    4452               0 :     if (fstart >= fend) {
    4453               0 :       continue;
    4454                 :     }
    4455                 : 
    4456                 :     // overlapping with the offset we want
    4457               0 :     gfxSkipCharsIterator iter = curr->EnsureTextRun(nsTextFrame::eInflated);
    4458               0 :     gfxTextRun* textRun = curr->GetTextRun(nsTextFrame::eInflated);
    4459               0 :     NS_ENSURE_TRUE(textRun, NS_ERROR_OUT_OF_MEMORY);
    4460                 : 
    4461               0 :     PRUint32 skipStart = iter.ConvertOriginalToSkipped(fstart);
    4462               0 :     PRUint32 skipEnd = iter.ConvertOriginalToSkipped(fend);
    4463                 :     aFontFaceList->AddFontsFromTextRun(textRun,
    4464                 :                                        skipStart,
    4465                 :                                        skipEnd - skipStart,
    4466               0 :                                        curr);
    4467                 :   } while (aFollowContinuations &&
    4468               0 :            (curr = static_cast<nsTextFrame*>(curr->GetNextContinuation())));
    4469                 : 
    4470               0 :   return NS_OK;
    4471                 : }
    4472                 : 
    4473                 : /* static */
    4474                 : size_t
    4475               0 : nsLayoutUtils::SizeOfTextRunsForFrames(nsIFrame* aFrame,
    4476                 :                                        nsMallocSizeOfFun aMallocSizeOf,
    4477                 :                                        bool clear)
    4478                 : {
    4479               0 :   NS_PRECONDITION(aFrame, "NULL frame pointer");
    4480                 : 
    4481               0 :   size_t total = 0;
    4482                 : 
    4483               0 :   if (aFrame->GetType() == nsGkAtoms::textFrame) {
    4484               0 :     nsTextFrame* textFrame = static_cast<nsTextFrame*>(aFrame);
    4485               0 :     for (PRUint32 i = 0; i < 2; ++i) {
    4486                 :       gfxTextRun *run = textFrame->GetTextRun(
    4487               0 :         (i != 0) ? nsTextFrame::eInflated : nsTextFrame::eNotInflated);
    4488               0 :       if (run) {
    4489               0 :         if (clear) {
    4490               0 :           run->ResetSizeOfAccountingFlags();
    4491                 :         } else {
    4492               0 :           total += run->MaybeSizeOfIncludingThis(aMallocSizeOf);
    4493                 :         }
    4494                 :       }
    4495                 :     }
    4496               0 :     return total;
    4497                 :   }
    4498                 : 
    4499               0 :   nsAutoTArray<nsIFrame::ChildList,4> childListArray;
    4500               0 :   aFrame->GetChildLists(&childListArray);
    4501                 : 
    4502               0 :   for (nsIFrame::ChildListArrayIterator childLists(childListArray);
    4503               0 :        !childLists.IsDone(); childLists.Next()) {
    4504               0 :     for (nsFrameList::Enumerator e(childLists.CurrentList());
    4505               0 :          !e.AtEnd(); e.Next()) {
    4506               0 :       total += SizeOfTextRunsForFrames(e.get(), aMallocSizeOf, clear);
    4507                 :     }
    4508                 :   }
    4509               0 :   return total;
    4510                 : }
    4511                 : 
    4512                 : /* static */
    4513                 : void
    4514            1404 : nsLayoutUtils::Initialize()
    4515                 : {
    4516                 :   mozilla::Preferences::AddUintVarCache(&sFontSizeInflationEmPerLine,
    4517            1404 :                                         "font.size.inflation.emPerLine");
    4518                 :   mozilla::Preferences::AddUintVarCache(&sFontSizeInflationMinTwips,
    4519            1404 :                                         "font.size.inflation.minTwips");
    4520            1404 : }
    4521                 : 
    4522                 : /* static */
    4523                 : void
    4524            1403 : nsLayoutUtils::Shutdown()
    4525                 : {
    4526            1403 :   if (sContentMap) {
    4527               0 :     delete sContentMap;
    4528               0 :     sContentMap = NULL;
    4529                 :   }
    4530            1403 : }
    4531                 : 
    4532                 : /* static */
    4533                 : void
    4534               0 : nsLayoutUtils::RegisterImageRequest(nsPresContext* aPresContext,
    4535                 :                                     imgIRequest* aRequest,
    4536                 :                                     bool* aRequestRegistered)
    4537                 : {
    4538               0 :   if (!aPresContext) {
    4539               0 :     return;
    4540                 :   }
    4541                 : 
    4542               0 :   if (aRequestRegistered && *aRequestRegistered) {
    4543                 :     // Our request is already registered with the refresh driver, so
    4544                 :     // no need to register it again.
    4545               0 :     return;
    4546                 :   }
    4547                 : 
    4548               0 :   if (aRequest) {
    4549               0 :     if (!aPresContext->RefreshDriver()->AddImageRequest(aRequest)) {
    4550               0 :       NS_WARNING("Unable to add image request");
    4551               0 :       return;
    4552                 :     }
    4553                 : 
    4554               0 :     if (aRequestRegistered) {
    4555               0 :       *aRequestRegistered = true;
    4556                 :     }
    4557                 :   }
    4558                 : }
    4559                 : 
    4560                 : /* static */
    4561                 : void
    4562               0 : nsLayoutUtils::RegisterImageRequestIfAnimated(nsPresContext* aPresContext,
    4563                 :                                               imgIRequest* aRequest,
    4564                 :                                               bool* aRequestRegistered)
    4565                 : {
    4566               0 :   if (!aPresContext) {
    4567               0 :     return;
    4568                 :   }
    4569                 : 
    4570               0 :   if (aRequestRegistered && *aRequestRegistered) {
    4571                 :     // Our request is already registered with the refresh driver, so
    4572                 :     // no need to register it again.
    4573               0 :     return;
    4574                 :   }
    4575                 : 
    4576               0 :   if (aRequest) {
    4577               0 :     nsCOMPtr<imgIContainer> image;
    4578               0 :     aRequest->GetImage(getter_AddRefs(image));
    4579               0 :     if (image) {
    4580                 : 
    4581                 :       // Check to verify that the image is animated. If so, then add it to the
    4582                 :       // list of images tracked by the refresh driver.
    4583               0 :       bool isAnimated = false;
    4584               0 :       nsresult rv = image->GetAnimated(&isAnimated);
    4585               0 :       if (NS_SUCCEEDED(rv) && isAnimated) {
    4586               0 :         if (!aPresContext->RefreshDriver()->AddImageRequest(aRequest)) {
    4587               0 :           NS_WARNING("Unable to add image request");
    4588                 :           return;
    4589                 :         }
    4590                 : 
    4591               0 :         if (aRequestRegistered) {
    4592               0 :           *aRequestRegistered = true;
    4593                 :         }
    4594                 :       }
    4595                 :     }
    4596                 :   }
    4597                 : }
    4598                 : 
    4599                 : /* static */
    4600                 : void
    4601               0 : nsLayoutUtils::DeregisterImageRequest(nsPresContext* aPresContext,
    4602                 :                                       imgIRequest* aRequest,
    4603                 :                                       bool* aRequestRegistered)
    4604                 : {
    4605               0 :   if (!aPresContext) {
    4606               0 :     return;
    4607                 :   }
    4608                 : 
    4609                 :   // Deregister our imgIRequest with the refresh driver to
    4610                 :   // complete tear-down, but only if it has been registered
    4611               0 :   if (aRequestRegistered && !*aRequestRegistered) {
    4612               0 :     return;
    4613                 :   }
    4614                 : 
    4615               0 :   if (aRequest) {
    4616               0 :     nsCOMPtr<imgIContainer> image;
    4617               0 :     aRequest->GetImage(getter_AddRefs(image));
    4618               0 :     if (image) {
    4619               0 :       aPresContext->RefreshDriver()->RemoveImageRequest(aRequest);
    4620                 : 
    4621               0 :       if (aRequestRegistered) {
    4622               0 :         *aRequestRegistered = false;
    4623                 :       }
    4624                 :     }
    4625                 :   }
    4626                 : }
    4627                 : 
    4628               0 : nsSetAttrRunnable::nsSetAttrRunnable(nsIContent* aContent, nsIAtom* aAttrName,
    4629                 :                                      const nsAString& aValue)
    4630                 :   : mContent(aContent),
    4631                 :     mAttrName(aAttrName),
    4632               0 :     mValue(aValue)
    4633                 : {
    4634               0 :   NS_ASSERTION(aContent && aAttrName, "Missing stuff, prepare to crash");
    4635               0 : }
    4636                 : 
    4637               0 : nsSetAttrRunnable::nsSetAttrRunnable(nsIContent* aContent, nsIAtom* aAttrName,
    4638                 :                                      PRInt32 aValue)
    4639                 :   : mContent(aContent),
    4640               0 :     mAttrName(aAttrName)
    4641                 : {
    4642               0 :   NS_ASSERTION(aContent && aAttrName, "Missing stuff, prepare to crash");
    4643               0 :   mValue.AppendInt(aValue);
    4644               0 : }
    4645                 : 
    4646                 : NS_IMETHODIMP
    4647               0 : nsSetAttrRunnable::Run()
    4648                 : {
    4649               0 :   return mContent->SetAttr(kNameSpaceID_None, mAttrName, mValue, true);
    4650                 : }
    4651                 : 
    4652               0 : nsUnsetAttrRunnable::nsUnsetAttrRunnable(nsIContent* aContent,
    4653                 :                                          nsIAtom* aAttrName)
    4654                 :   : mContent(aContent),
    4655               0 :     mAttrName(aAttrName)
    4656                 : {
    4657               0 :   NS_ASSERTION(aContent && aAttrName, "Missing stuff, prepare to crash");
    4658               0 : }
    4659                 : 
    4660                 : NS_IMETHODIMP
    4661               0 : nsUnsetAttrRunnable::Run()
    4662                 : {
    4663               0 :   return mContent->UnsetAttr(kNameSpaceID_None, mAttrName, true);
    4664                 : }
    4665                 : 
    4666               0 : nsReflowFrameRunnable::nsReflowFrameRunnable(nsIFrame* aFrame,
    4667                 :                           nsIPresShell::IntrinsicDirty aIntrinsicDirty,
    4668                 :                           nsFrameState aBitToAdd)
    4669                 :   : mWeakFrame(aFrame),
    4670                 :     mIntrinsicDirty(aIntrinsicDirty),
    4671               0 :     mBitToAdd(aBitToAdd)
    4672                 : {
    4673               0 : }
    4674                 : 
    4675                 : NS_IMETHODIMP
    4676               0 : nsReflowFrameRunnable::Run()
    4677                 : {
    4678               0 :   if (mWeakFrame.IsAlive()) {
    4679               0 :     mWeakFrame->PresContext()->PresShell()->
    4680               0 :       FrameNeedsReflow(mWeakFrame, mIntrinsicDirty, mBitToAdd);
    4681                 :   }
    4682               0 :   return NS_OK;
    4683                 : }
    4684                 : 
    4685                 : /**
    4686                 :  * Compute the minimum font size inside of a container with the given
    4687                 :  * width, such that **when the user zooms the container to fill the full
    4688                 :  * width of the device**, the fonts satisfy our minima.
    4689                 :  */
    4690                 : static nscoord
    4691               0 : MinimumFontSizeFor(nsPresContext* aPresContext, nscoord aContainerWidth)
    4692                 : {
    4693               0 :   if (sFontSizeInflationEmPerLine == 0 && sFontSizeInflationMinTwips == 0) {
    4694               0 :     return 0;
    4695                 :   }
    4696                 : 
    4697                 :   // Clamp the container width to the device dimensions
    4698               0 :   nscoord iFrameWidth = aPresContext->GetVisibleArea().width;
    4699               0 :   nscoord effectiveContainerWidth = NS_MIN(iFrameWidth, aContainerWidth);
    4700                 : 
    4701               0 :   nscoord byLine = 0, byInch = 0;
    4702               0 :   if (sFontSizeInflationEmPerLine != 0) {
    4703               0 :     byLine = effectiveContainerWidth / sFontSizeInflationEmPerLine;
    4704                 :   }
    4705               0 :   if (sFontSizeInflationMinTwips != 0) {
    4706                 :     // REVIEW: Is this giving us app units and sizes *not* counting
    4707                 :     // viewport scaling?
    4708               0 :     nsDeviceContext *dx = aPresContext->DeviceContext();
    4709               0 :     nsRect clientRect;
    4710               0 :     dx->GetClientRect(clientRect); // FIXME: GetClientRect looks expensive
    4711                 :     float deviceWidthInches =
    4712               0 :       float(clientRect.width) / float(dx->AppUnitsPerPhysicalInch());
    4713                 :     byInch = NSToCoordRound(effectiveContainerWidth /
    4714                 :                             (deviceWidthInches * 1440 /
    4715               0 :                              sFontSizeInflationMinTwips ));
    4716                 :   }
    4717               0 :   return NS_MAX(byLine, byInch);
    4718                 : }
    4719                 : 
    4720                 : /* static */ float
    4721               0 : nsLayoutUtils::FontSizeInflationInner(const nsIFrame *aFrame,
    4722                 :                                       nscoord aMinFontSize)
    4723                 : {
    4724                 :   // Note that line heights should be inflated by the same ratio as the
    4725                 :   // font size of the same text; thus we operate only on the font size
    4726                 :   // even when we're scaling a line height.
    4727               0 :   nscoord styleFontSize = aFrame->GetStyleFont()->mFont.size;
    4728               0 :   if (styleFontSize <= 0) {
    4729                 :     // Never scale zero font size.
    4730               0 :     return 1.0;
    4731                 :   }
    4732                 : 
    4733               0 :   if (aMinFontSize <= 0) {
    4734                 :     // No need to scale.
    4735               0 :     return 1.0;
    4736                 :   }
    4737                 : 
    4738                 :   // Scale everything from 0-1.5 times min to instead fit in the range
    4739                 :   // 1-1.5 times min, so that we still show some distinction rather than
    4740                 :   // just enforcing a minimum.
    4741                 :   // FIXME: Fiddle with this algorithm; maybe have prefs to control it?
    4742               0 :   float ratio = float(styleFontSize) / float(aMinFontSize);
    4743               0 :   if (ratio >= 1.5f) {
    4744                 :     // If we're already at 1.5 or more times the minimum, don't scale.
    4745               0 :     return 1.0;
    4746                 :   }
    4747                 : 
    4748                 :   // To scale 0-1.5 times min to instead be 1-1.5 times min, we want
    4749                 :   // to the desired multiple of min to be 1 + (ratio/3) (where ratio
    4750                 :   // is our input's multiple of min).  The scaling needed to produce
    4751                 :   // that is that divided by |ratio|, or:
    4752               0 :   return (1.0f / ratio) + (1.0f / 3.0f);
    4753                 : }
    4754                 : 
    4755                 : static bool
    4756               0 : ShouldInflateFontsForContainer(const nsIFrame *aFrame)
    4757                 : {
    4758                 :   // We only want to inflate fonts for text that is in a place
    4759                 :   // with room to expand.  The question is what the best heuristic for
    4760                 :   // that is...
    4761                 :   // For now, we're going to use NS_FRAME_IN_CONSTRAINED_HEIGHT, which
    4762                 :   // indicates whether the frame is inside something with a constrained
    4763                 :   // height (propagating down the tree), but the propagation stops when
    4764                 :   // we hit overflow-y: scroll or auto.
    4765               0 :   const nsStyleText* styleText = aFrame->GetStyleText();
    4766                 : 
    4767                 :   return styleText->mTextSizeAdjust != NS_STYLE_TEXT_SIZE_ADJUST_NONE &&
    4768               0 :          !(aFrame->GetStateBits() & NS_FRAME_IN_CONSTRAINED_HEIGHT) &&
    4769                 :          // We also want to disable font inflation for containers that have
    4770                 :          // preformatted text.
    4771               0 :          styleText->WhiteSpaceCanWrap();
    4772                 : }
    4773                 : 
    4774                 : nscoord
    4775               0 : nsLayoutUtils::InflationMinFontSizeFor(const nsIFrame *aFrame,
    4776                 :                                        WidthDetermination aWidthDetermination)
    4777                 : {
    4778                 : #ifdef DEBUG
    4779               0 :   if (aWidthDetermination == eNotInReflow) {
    4780                 :     // Check that neither this frame nor any of its ancestors are
    4781                 :     // currently being reflowed.
    4782                 :     // It's ok for box frames (but not arbitrary ancestors of box frames)
    4783                 :     // since they set their size before reflow.
    4784               0 :     if (!(aFrame->IsBoxFrame() && IsContainerForFontSizeInflation(aFrame))) {
    4785               0 :       for (const nsIFrame *f = aFrame; f; f = f->GetParent()) {
    4786               0 :         NS_ABORT_IF_FALSE(!(f->GetStateBits() & NS_FRAME_IN_REFLOW),
    4787                 :                           "must call nsHTMLReflowState& version during reflow");
    4788                 :       }
    4789                 :     }
    4790                 :     // It's ok if frames are dirty, or even if they've never been
    4791                 :     // reflowed, since they will be eventually and then we'll get the
    4792                 :     // right size.
    4793                 :   }
    4794                 : #endif
    4795                 : 
    4796               0 :   if (!FontSizeInflationEnabled(aFrame->PresContext())) {
    4797               0 :     return 0;
    4798                 :   }
    4799                 : 
    4800               0 :   if (aWidthDetermination == eInReflow) {
    4801               0 :     nsPresContext *presContext = aFrame->PresContext();
    4802               0 :     nsIFrame *container = presContext->mCurrentInflationContainer;
    4803               0 :     if (!container || !ShouldInflateFontsForContainer(container)) {
    4804               0 :       return 0;
    4805                 :     }
    4806                 :     return MinimumFontSizeFor(presContext,
    4807               0 :                               presContext->mCurrentInflationContainerWidth);
    4808                 :   }
    4809                 : 
    4810               0 :   for (const nsIFrame *f = aFrame; f; f = f->GetParent()) {
    4811               0 :     if (IsContainerForFontSizeInflation(f)) {
    4812               0 :       if (!ShouldInflateFontsForContainer(f)) {
    4813               0 :         return 0;
    4814                 :       }
    4815                 : 
    4816                 :       return MinimumFontSizeFor(aFrame->PresContext(),
    4817               0 :                                 f->GetContentRect().width);
    4818                 :     }
    4819                 :   }
    4820                 : 
    4821               0 :   NS_ABORT_IF_FALSE(false, "root should always be container");
    4822                 : 
    4823               0 :   return 0;
    4824                 : }
    4825                 : 
    4826                 : float
    4827               0 : nsLayoutUtils::FontSizeInflationFor(const nsIFrame *aFrame,
    4828                 :                                     WidthDetermination aWidthDetermination)
    4829                 : {
    4830                 : #ifdef DEBUG
    4831               0 :   if (aWidthDetermination == eNotInReflow) {
    4832                 :     // Check that neither this frame nor any of its ancestors are
    4833                 :     // currently being reflowed.
    4834                 :     // It's ok for box frames (but not arbitrary ancestors of box frames)
    4835                 :     // since they set their size before reflow.
    4836               0 :     if (!(aFrame->IsBoxFrame() && IsContainerForFontSizeInflation(aFrame))) {
    4837               0 :       for (const nsIFrame *f = aFrame; f; f = f->GetParent()) {
    4838               0 :         NS_ABORT_IF_FALSE(!(f->GetStateBits() & NS_FRAME_IN_REFLOW),
    4839                 :                           "must call nsHTMLReflowState& version during reflow");
    4840                 :       }
    4841                 :     }
    4842                 :     // It's ok if frames are dirty, or even if they've never been
    4843                 :     // reflowed, since they will be eventually and then we'll get the
    4844                 :     // right size.
    4845                 :   }
    4846                 : #endif
    4847                 : 
    4848               0 :   if (!FontSizeInflationEnabled(aFrame->PresContext())) {
    4849               0 :     return 1.0;
    4850                 :   }
    4851                 : 
    4852                 :   return FontSizeInflationInner(aFrame,
    4853                 :                                 InflationMinFontSizeFor(aFrame,
    4854               0 :                                                         aWidthDetermination));
    4855                 : }
    4856                 : 
    4857                 : /* static */ bool
    4858               0 : nsLayoutUtils::FontSizeInflationEnabled(nsPresContext *aPresContext)
    4859                 : {
    4860               0 :   if ((sFontSizeInflationEmPerLine == 0 &&
    4861                 :        sFontSizeInflationMinTwips == 0) ||
    4862               0 :        aPresContext->IsChrome()) {
    4863               0 :     return false;
    4864                 :   }
    4865                 : 
    4866                 :   ViewportInfo vInf =
    4867               0 :     nsContentUtils::GetViewportInfo(aPresContext->PresShell()->GetDocument());
    4868                 : 
    4869               0 :   if (vInf.defaultZoom >= 1.0 || vInf.autoSize) {
    4870               0 :     return false;
    4871                 :   }
    4872                 : 
    4873               0 :   return true;
    4874            4392 : }

Generated by: LCOV version 1.7