LCOV - app.info - layout/base/nsLayoutUtils.cpp

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