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 Novell code.
17 : *
18 : * The Initial Developer of the Original Code is Novell Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 2006
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * robert@ocallahan.org
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK *****
38 : */
39 :
40 : /*
41 : * structures that represent things to be painted (ordered in z-order),
42 : * used during painting and hit testing
43 : */
44 :
45 : #include "nsDisplayList.h"
46 :
47 : #include "nsCSSRendering.h"
48 : #include "nsRenderingContext.h"
49 : #include "nsISelectionController.h"
50 : #include "nsIPresShell.h"
51 : #include "nsRegion.h"
52 : #include "nsFrameManager.h"
53 : #include "gfxContext.h"
54 : #include "nsStyleStructInlines.h"
55 : #include "nsStyleTransformMatrix.h"
56 : #include "gfxMatrix.h"
57 : #include "nsSVGIntegrationUtils.h"
58 : #include "nsLayoutUtils.h"
59 : #include "nsIScrollableFrame.h"
60 : #include "nsThemeConstants.h"
61 :
62 : #include "imgIContainer.h"
63 : #include "nsIInterfaceRequestorUtils.h"
64 : #include "BasicLayers.h"
65 : #include "nsBoxFrame.h"
66 : #include "nsViewportFrame.h"
67 : #include "nsSVGEffects.h"
68 : #include "nsSVGClipPathFrame.h"
69 :
70 : using namespace mozilla;
71 : using namespace mozilla::layers;
72 : typedef FrameMetrics::ViewID ViewID;
73 :
74 0 : nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
75 : Mode aMode, bool aBuildCaret)
76 : : mReferenceFrame(aReferenceFrame),
77 : mIgnoreScrollFrame(nsnull),
78 : mCurrentTableItem(nsnull),
79 : mFinalTransparentRegion(nsnull),
80 : mMode(aMode),
81 : mBuildCaret(aBuildCaret),
82 : mIgnoreSuppression(false),
83 : mHadToIgnoreSuppression(false),
84 : mIsAtRootOfPseudoStackingContext(false),
85 : mIncludeAllOutOfFlows(false),
86 : mSelectedFramesOnly(false),
87 : mAccurateVisibleRegions(false),
88 : mInTransform(false),
89 : mSyncDecodeImages(false),
90 : mIsPaintingToWindow(false),
91 : mSnappingEnabled(mMode != EVENT_DELIVERY),
92 : mHasDisplayPort(false),
93 0 : mHasFixedItems(false)
94 : {
95 0 : MOZ_COUNT_CTOR(nsDisplayListBuilder);
96 : PL_InitArenaPool(&mPool, "displayListArena", 1024,
97 0 : NS_MAX(NS_ALIGNMENT_OF(void*),NS_ALIGNMENT_OF(double))-1);
98 :
99 0 : nsPresContext* pc = aReferenceFrame->PresContext();
100 0 : nsIPresShell *shell = pc->PresShell();
101 0 : if (pc->IsRenderingOnlySelection()) {
102 0 : nsCOMPtr<nsISelectionController> selcon(do_QueryInterface(shell));
103 0 : if (selcon) {
104 0 : selcon->GetSelection(nsISelectionController::SELECTION_NORMAL,
105 0 : getter_AddRefs(mBoundingSelection));
106 : }
107 : }
108 :
109 0 : if(mReferenceFrame->GetType() == nsGkAtoms::viewportFrame) {
110 0 : ViewportFrame* viewportFrame = static_cast<ViewportFrame*>(mReferenceFrame);
111 0 : if (!viewportFrame->GetChildList(nsIFrame::kFixedList).IsEmpty()) {
112 0 : mHasFixedItems = true;
113 : }
114 : }
115 :
116 0 : LayerBuilder()->Init(this);
117 :
118 : PR_STATIC_ASSERT(nsDisplayItem::TYPE_MAX < (1 << nsDisplayItem::TYPE_BITS));
119 0 : }
120 :
121 0 : static void MarkFrameForDisplay(nsIFrame* aFrame, nsIFrame* aStopAtFrame) {
122 0 : nsFrameManager* frameManager = aFrame->PresContext()->PresShell()->FrameManager();
123 :
124 0 : for (nsIFrame* f = aFrame; f;
125 : f = nsLayoutUtils::GetParentOrPlaceholderFor(frameManager, f)) {
126 0 : if (f->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)
127 0 : return;
128 0 : f->AddStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO);
129 0 : if (f == aStopAtFrame) {
130 : // we've reached a frame that we know will be painted, so we can stop.
131 0 : break;
132 : }
133 : }
134 : }
135 :
136 0 : static bool IsFixedFrame(nsIFrame* aFrame)
137 : {
138 0 : return aFrame && aFrame->GetParent() && !aFrame->GetParent()->GetParent();
139 : }
140 :
141 0 : static bool IsFixedItem(nsDisplayItem *aItem, nsDisplayListBuilder* aBuilder)
142 : {
143 : nsIFrame* activeScrolledRoot =
144 0 : nsLayoutUtils::GetActiveScrolledRootFor(aItem, aBuilder);
145 : return activeScrolledRoot &&
146 : !nsLayoutUtils::ScrolledByViewportScrolling(activeScrolledRoot,
147 0 : aBuilder);
148 : }
149 :
150 0 : static bool ForceVisiblityForFixedItem(nsDisplayListBuilder* aBuilder,
151 : nsDisplayItem* aItem)
152 : {
153 0 : return aBuilder->GetDisplayPort() && aBuilder->GetHasFixedItems() &&
154 0 : IsFixedItem(aItem, aBuilder);
155 : }
156 :
157 0 : void nsDisplayListBuilder::SetDisplayPort(const nsRect& aDisplayPort)
158 : {
159 0 : static bool fixedPositionLayersEnabled = getenv("MOZ_ENABLE_FIXED_POSITION_LAYERS") != 0;
160 0 : if (fixedPositionLayersEnabled) {
161 0 : mHasDisplayPort = true;
162 0 : mDisplayPort = aDisplayPort;
163 : }
164 0 : }
165 :
166 0 : void nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame,
167 : nsIFrame* aFrame,
168 : const nsRect& aDirtyRect)
169 : {
170 0 : nsRect dirty = aDirtyRect - aFrame->GetOffsetTo(aDirtyFrame);
171 0 : nsRect overflowRect = aFrame->GetVisualOverflowRect();
172 :
173 0 : if (mHasDisplayPort && IsFixedFrame(aFrame)) {
174 0 : dirty = overflowRect;
175 : }
176 :
177 0 : if (!dirty.IntersectRect(dirty, overflowRect))
178 : return;
179 : aFrame->Properties().Set(nsDisplayListBuilder::OutOfFlowDirtyRectProperty(),
180 0 : new nsRect(dirty));
181 :
182 0 : MarkFrameForDisplay(aFrame, aDirtyFrame);
183 : }
184 :
185 0 : static void UnmarkFrameForDisplay(nsIFrame* aFrame) {
186 0 : nsPresContext* presContext = aFrame->PresContext();
187 : presContext->PropertyTable()->
188 0 : Delete(aFrame, nsDisplayListBuilder::OutOfFlowDirtyRectProperty());
189 :
190 0 : nsFrameManager* frameManager = presContext->PresShell()->FrameManager();
191 :
192 0 : for (nsIFrame* f = aFrame; f;
193 : f = nsLayoutUtils::GetParentOrPlaceholderFor(frameManager, f)) {
194 0 : if (!(f->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO))
195 0 : return;
196 0 : f->RemoveStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO);
197 : }
198 : }
199 :
200 0 : static void RecordFrameMetrics(nsIFrame* aForFrame,
201 : nsIFrame* aScrollFrame,
202 : ContainerLayer* aRoot,
203 : const nsRect& aVisibleRect,
204 : const nsRect& aViewport,
205 : nsRect* aDisplayPort,
206 : ViewID aScrollId,
207 : const nsDisplayItem::ContainerParameters& aContainerParameters) {
208 0 : nsPresContext* presContext = aForFrame->PresContext();
209 0 : PRInt32 auPerDevPixel = presContext->AppUnitsPerDevPixel();
210 :
211 : nsIntRect visible = aVisibleRect.ScaleToNearestPixels(
212 0 : aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
213 0 : aRoot->SetVisibleRegion(nsIntRegion(visible));
214 :
215 0 : FrameMetrics metrics;
216 :
217 : metrics.mViewport = aViewport.ScaleToNearestPixels(
218 0 : aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
219 :
220 0 : if (aDisplayPort) {
221 : metrics.mDisplayPort = aDisplayPort->ScaleToNearestPixels(
222 0 : aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
223 : }
224 :
225 0 : nsIScrollableFrame* scrollableFrame = nsnull;
226 0 : if (aScrollFrame)
227 0 : scrollableFrame = aScrollFrame->GetScrollTargetFrame();
228 :
229 0 : if (scrollableFrame) {
230 : nsSize contentSize =
231 0 : scrollableFrame->GetScrollRange().Size() +
232 0 : scrollableFrame->GetScrollPortRect().Size();
233 : metrics.mContentSize = contentSize.ScaleToNearestPixels(
234 0 : aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
235 0 : metrics.mViewportScrollOffset = scrollableFrame->GetScrollPosition().ScaleToNearestPixels(
236 0 : aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
237 : }
238 : else {
239 0 : nsSize contentSize = aForFrame->GetSize();
240 : metrics.mContentSize = contentSize.ScaleToNearestPixels(
241 0 : aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
242 : }
243 :
244 0 : metrics.mScrollId = aScrollId;
245 0 : aRoot->SetFrameMetrics(metrics);
246 0 : }
247 :
248 0 : nsDisplayListBuilder::~nsDisplayListBuilder() {
249 0 : NS_ASSERTION(mFramesMarkedForDisplay.Length() == 0,
250 : "All frames should have been unmarked");
251 0 : NS_ASSERTION(mPresShellStates.Length() == 0,
252 : "All presshells should have been exited");
253 0 : NS_ASSERTION(!mCurrentTableItem, "No table item should be active");
254 :
255 0 : PL_FreeArenaPool(&mPool);
256 0 : PL_FinishArenaPool(&mPool);
257 0 : MOZ_COUNT_DTOR(nsDisplayListBuilder);
258 0 : }
259 :
260 : PRUint32
261 0 : nsDisplayListBuilder::GetBackgroundPaintFlags() {
262 0 : PRUint32 flags = 0;
263 0 : if (mSyncDecodeImages) {
264 0 : flags |= nsCSSRendering::PAINTBG_SYNC_DECODE_IMAGES;
265 : }
266 0 : if (mIsPaintingToWindow) {
267 0 : flags |= nsCSSRendering::PAINTBG_TO_WINDOW;
268 : }
269 0 : return flags;
270 : }
271 :
272 0 : static PRUint64 RegionArea(const nsRegion& aRegion)
273 : {
274 0 : PRUint64 area = 0;
275 0 : nsRegionRectIterator iter(aRegion);
276 : const nsRect* r;
277 0 : while ((r = iter.Next()) != nsnull) {
278 0 : area += PRUint64(r->width)*r->height;
279 : }
280 0 : return area;
281 : }
282 :
283 : void
284 0 : nsDisplayListBuilder::SubtractFromVisibleRegion(nsRegion* aVisibleRegion,
285 : const nsRegion& aRegion)
286 : {
287 0 : if (aRegion.IsEmpty())
288 0 : return;
289 :
290 0 : nsRegion tmp;
291 0 : tmp.Sub(*aVisibleRegion, aRegion);
292 : // Don't let *aVisibleRegion get too complex, but don't let it fluff out
293 : // to its bounds either, which can be very bad (see bug 516740).
294 : // Do let aVisibleRegion get more complex if by doing so we reduce its
295 : // area by at least half.
296 0 : if (GetAccurateVisibleRegions() || tmp.GetNumRects() <= 15 ||
297 0 : RegionArea(tmp) <= RegionArea(*aVisibleRegion)/2) {
298 0 : *aVisibleRegion = tmp;
299 : }
300 : }
301 :
302 : nsCaret *
303 0 : nsDisplayListBuilder::GetCaret() {
304 0 : nsRefPtr<nsCaret> caret = CurrentPresShellState()->mPresShell->GetCaret();
305 0 : return caret;
306 : }
307 :
308 : void
309 0 : nsDisplayListBuilder::EnterPresShell(nsIFrame* aReferenceFrame,
310 : const nsRect& aDirtyRect) {
311 0 : PresShellState* state = mPresShellStates.AppendElement();
312 0 : if (!state)
313 0 : return;
314 0 : state->mPresShell = aReferenceFrame->PresContext()->PresShell();
315 0 : state->mCaretFrame = nsnull;
316 0 : state->mFirstFrameMarkedForDisplay = mFramesMarkedForDisplay.Length();
317 :
318 0 : state->mPresShell->UpdateCanvasBackground();
319 :
320 0 : if (mIsPaintingToWindow) {
321 0 : mReferenceFrame->AddPaintedPresShell(state->mPresShell);
322 :
323 0 : state->mPresShell->IncrementPaintCount();
324 : }
325 :
326 0 : bool buildCaret = mBuildCaret;
327 0 : if (mIgnoreSuppression || !state->mPresShell->IsPaintingSuppressed()) {
328 0 : if (state->mPresShell->IsPaintingSuppressed()) {
329 0 : mHadToIgnoreSuppression = true;
330 : }
331 0 : state->mIsBackgroundOnly = false;
332 : } else {
333 0 : state->mIsBackgroundOnly = true;
334 0 : buildCaret = false;
335 : }
336 :
337 0 : if (!buildCaret)
338 0 : return;
339 :
340 0 : nsRefPtr<nsCaret> caret = state->mPresShell->GetCaret();
341 0 : state->mCaretFrame = caret->GetCaretFrame();
342 :
343 0 : if (state->mCaretFrame) {
344 : // Check if the dirty rect intersects with the caret's dirty rect.
345 : nsRect caretRect =
346 0 : caret->GetCaretRect() + state->mCaretFrame->GetOffsetTo(aReferenceFrame);
347 0 : if (caretRect.Intersects(aDirtyRect)) {
348 : // Okay, our rects intersect, let's mark the frame and all of its ancestors.
349 0 : mFramesMarkedForDisplay.AppendElement(state->mCaretFrame);
350 0 : MarkFrameForDisplay(state->mCaretFrame, nsnull);
351 : }
352 : }
353 : }
354 :
355 : void
356 0 : nsDisplayListBuilder::LeavePresShell(nsIFrame* aReferenceFrame,
357 : const nsRect& aDirtyRect) {
358 0 : if (CurrentPresShellState()->mPresShell != aReferenceFrame->PresContext()->PresShell()) {
359 : // Must have not allocated a state for this presshell, presumably due
360 : // to OOM.
361 0 : return;
362 : }
363 :
364 : // Unmark and pop off the frames marked for display in this pres shell.
365 0 : PRUint32 firstFrameForShell = CurrentPresShellState()->mFirstFrameMarkedForDisplay;
366 0 : for (PRUint32 i = firstFrameForShell;
367 0 : i < mFramesMarkedForDisplay.Length(); ++i) {
368 0 : UnmarkFrameForDisplay(mFramesMarkedForDisplay[i]);
369 : }
370 0 : mFramesMarkedForDisplay.SetLength(firstFrameForShell);
371 0 : mPresShellStates.SetLength(mPresShellStates.Length() - 1);
372 : }
373 :
374 : void
375 0 : nsDisplayListBuilder::MarkFramesForDisplayList(nsIFrame* aDirtyFrame,
376 : const nsFrameList& aFrames,
377 : const nsRect& aDirtyRect) {
378 0 : for (nsFrameList::Enumerator e(aFrames); !e.AtEnd(); e.Next()) {
379 0 : mFramesMarkedForDisplay.AppendElement(e.get());
380 0 : MarkOutOfFlowFrameForDisplay(aDirtyFrame, e.get(), aDirtyRect);
381 : }
382 0 : }
383 :
384 : void*
385 0 : nsDisplayListBuilder::Allocate(size_t aSize) {
386 : void *tmp;
387 0 : PL_ARENA_ALLOCATE(tmp, &mPool, aSize);
388 0 : return tmp;
389 : }
390 :
391 0 : void nsDisplayListSet::MoveTo(const nsDisplayListSet& aDestination) const
392 : {
393 0 : aDestination.BorderBackground()->AppendToTop(BorderBackground());
394 0 : aDestination.BlockBorderBackgrounds()->AppendToTop(BlockBorderBackgrounds());
395 0 : aDestination.Floats()->AppendToTop(Floats());
396 0 : aDestination.Content()->AppendToTop(Content());
397 0 : aDestination.PositionedDescendants()->AppendToTop(PositionedDescendants());
398 0 : aDestination.Outlines()->AppendToTop(Outlines());
399 0 : }
400 :
401 : void
402 0 : nsDisplayList::FlattenTo(nsTArray<nsDisplayItem*>* aElements) {
403 : nsDisplayItem* item;
404 0 : while ((item = RemoveBottom()) != nsnull) {
405 0 : if (item->GetType() == nsDisplayItem::TYPE_WRAP_LIST) {
406 0 : item->GetList()->FlattenTo(aElements);
407 0 : item->~nsDisplayItem();
408 : } else {
409 0 : aElements->AppendElement(item);
410 : }
411 : }
412 0 : }
413 :
414 : nsRect
415 0 : nsDisplayList::GetBounds(nsDisplayListBuilder* aBuilder) const {
416 0 : nsRect bounds;
417 0 : for (nsDisplayItem* i = GetBottom(); i != nsnull; i = i->GetAbove()) {
418 0 : bounds.UnionRect(bounds, i->GetBounds(aBuilder));
419 : }
420 : return bounds;
421 : }
422 :
423 : bool
424 0 : nsDisplayList::ComputeVisibilityForRoot(nsDisplayListBuilder* aBuilder,
425 : nsRegion* aVisibleRegion) {
426 0 : nsRegion r;
427 0 : r.And(*aVisibleRegion, GetBounds(aBuilder));
428 0 : return ComputeVisibilityForSublist(aBuilder, aVisibleRegion, r.GetBounds(), r.GetBounds());
429 : }
430 :
431 : static nsRegion
432 0 : TreatAsOpaque(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder,
433 : bool* aTransparentBackground)
434 : {
435 0 : nsRegion opaque = aItem->GetOpaqueRegion(aBuilder, aTransparentBackground);
436 0 : if (aBuilder->IsForPluginGeometry()) {
437 : // Treat all chrome items as opaque, unless their frames are opacity:0.
438 : // Since opacity:0 frames generate an nsDisplayOpacity, that item will
439 : // not be treated as opaque here, so opacity:0 chrome content will be
440 : // effectively ignored, as it should be.
441 0 : nsIFrame* f = aItem->GetUnderlyingFrame();
442 0 : if (f && f->PresContext()->IsChrome() && f->GetStyleDisplay()->mOpacity != 0.0) {
443 0 : opaque = aItem->GetBounds(aBuilder);
444 : }
445 : }
446 : return opaque;
447 : }
448 :
449 : static nsRect
450 0 : GetDisplayPortBounds(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem)
451 : {
452 : // GetDisplayPortBounds() rectangle is used in order to restrict fixed aItem's
453 : // visible bounds. nsDisplayTransform bounds already take item's
454 : // transform into account, so there is no need to apply it here one more time.
455 : // Start TransformRectToBoundsInAncestor() calculations from aItem's frame
456 : // parent in this case.
457 0 : nsIFrame* frame = aItem->GetUnderlyingFrame();
458 0 : if (aItem->GetType() == nsDisplayItem::TYPE_TRANSFORM) {
459 0 : frame = nsLayoutUtils::GetCrossDocParentFrame(frame);
460 : }
461 :
462 0 : const nsRect* displayport = aBuilder->GetDisplayPort();
463 : nsRect result = nsLayoutUtils::TransformAncestorRectToFrame(
464 : frame,
465 0 : nsRect(0, 0, displayport->width, displayport->height),
466 0 : aBuilder->ReferenceFrame());
467 0 : result.MoveBy(aBuilder->ToReferenceFrame(frame));
468 : return result;
469 : }
470 :
471 : bool
472 0 : nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder,
473 : nsRegion* aVisibleRegion,
474 : const nsRect& aListVisibleBounds,
475 : const nsRect& aAllowVisibleRegionExpansion) {
476 : #ifdef DEBUG
477 0 : nsRegion r;
478 0 : r.And(*aVisibleRegion, GetBounds(aBuilder));
479 0 : NS_ASSERTION(r.GetBounds().IsEqualInterior(aListVisibleBounds),
480 : "bad aListVisibleBounds");
481 : #endif
482 0 : mVisibleRect = aListVisibleBounds;
483 0 : bool anyVisible = false;
484 :
485 0 : nsAutoTArray<nsDisplayItem*, 512> elements;
486 0 : FlattenTo(&elements);
487 :
488 0 : bool forceTransparentSurface = false;
489 :
490 0 : for (PRInt32 i = elements.Length() - 1; i >= 0; --i) {
491 0 : nsDisplayItem* item = elements[i];
492 0 : nsDisplayItem* belowItem = i < 1 ? nsnull : elements[i - 1];
493 :
494 0 : if (belowItem && item->TryMerge(aBuilder, belowItem)) {
495 0 : belowItem->~nsDisplayItem();
496 0 : elements.ReplaceElementsAt(i - 1, 1, item);
497 0 : continue;
498 : }
499 :
500 0 : nsDisplayList* list = item->GetList();
501 0 : if (list && item->ShouldFlattenAway(aBuilder)) {
502 : // The elements on the list >= i no longer serve any use.
503 0 : elements.SetLength(i);
504 0 : list->FlattenTo(&elements);
505 0 : i = elements.Length();
506 0 : item->~nsDisplayItem();
507 0 : continue;
508 : }
509 :
510 0 : nsRect bounds = item->GetBounds(aBuilder);
511 :
512 0 : nsRegion itemVisible;
513 0 : if (ForceVisiblityForFixedItem(aBuilder, item)) {
514 0 : itemVisible.And(GetDisplayPortBounds(aBuilder, item), bounds);
515 : } else {
516 0 : itemVisible.And(*aVisibleRegion, bounds);
517 : }
518 0 : item->mVisibleRect = itemVisible.GetBounds();
519 :
520 0 : if (item->ComputeVisibility(aBuilder, aVisibleRegion, aAllowVisibleRegionExpansion)) {
521 0 : anyVisible = true;
522 0 : bool transparentBackground = false;
523 0 : nsRegion opaque = TreatAsOpaque(item, aBuilder, &transparentBackground);
524 : // Subtract opaque item from the visible region
525 0 : aBuilder->SubtractFromVisibleRegion(aVisibleRegion, opaque);
526 0 : forceTransparentSurface = forceTransparentSurface || transparentBackground;
527 : }
528 0 : AppendToBottom(item);
529 : }
530 :
531 0 : mIsOpaque = !aVisibleRegion->Intersects(mVisibleRect);
532 0 : mForceTransparentSurface = forceTransparentSurface;
533 : #ifdef DEBUG
534 0 : mDidComputeVisibility = true;
535 : #endif
536 0 : return anyVisible;
537 : }
538 :
539 0 : void nsDisplayList::PaintRoot(nsDisplayListBuilder* aBuilder,
540 : nsRenderingContext* aCtx,
541 : PRUint32 aFlags) const {
542 0 : PaintForFrame(aBuilder, aCtx, aBuilder->ReferenceFrame(), aFlags);
543 0 : }
544 :
545 : /**
546 : * We paint by executing a layer manager transaction, constructing a
547 : * single layer representing the display list, and then making it the
548 : * root of the layer manager, drawing into the ThebesLayers.
549 : */
550 0 : void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder,
551 : nsRenderingContext* aCtx,
552 : nsIFrame* aForFrame,
553 : PRUint32 aFlags) const {
554 0 : NS_ASSERTION(mDidComputeVisibility,
555 : "Must call ComputeVisibility before calling Paint");
556 :
557 0 : nsRefPtr<LayerManager> layerManager;
558 0 : bool allowRetaining = false;
559 0 : bool doBeginTransaction = true;
560 0 : if (aFlags & PAINT_USE_WIDGET_LAYERS) {
561 0 : nsIFrame* referenceFrame = aBuilder->ReferenceFrame();
562 0 : NS_ASSERTION(referenceFrame == nsLayoutUtils::GetDisplayRootFrame(referenceFrame),
563 : "Reference frame must be a display root for us to use the layer manager");
564 0 : nsIWidget* window = referenceFrame->GetNearestWidget();
565 0 : if (window) {
566 0 : layerManager = window->GetLayerManager(&allowRetaining);
567 0 : if (layerManager) {
568 0 : doBeginTransaction = !(aFlags & PAINT_EXISTING_TRANSACTION);
569 : }
570 : }
571 : }
572 0 : if (!layerManager) {
573 0 : if (!aCtx) {
574 0 : NS_WARNING("Nowhere to paint into");
575 : return;
576 : }
577 0 : layerManager = new BasicLayerManager();
578 : }
579 :
580 0 : if (aFlags & PAINT_FLUSH_LAYERS) {
581 0 : FrameLayerBuilder::InvalidateAllLayers(layerManager);
582 : }
583 :
584 0 : if (doBeginTransaction) {
585 0 : if (aCtx) {
586 0 : layerManager->BeginTransactionWithTarget(aCtx->ThebesContext());
587 : } else {
588 0 : layerManager->BeginTransaction();
589 : }
590 : }
591 0 : if (allowRetaining) {
592 0 : aBuilder->LayerBuilder()->DidBeginRetainedLayerTransaction(layerManager);
593 : }
594 :
595 0 : nsPresContext* presContext = aForFrame->PresContext();
596 0 : nsIPresShell* presShell = presContext->GetPresShell();
597 :
598 : nsDisplayItem::ContainerParameters containerParameters
599 0 : (presShell->GetXResolution(), presShell->GetYResolution());
600 : nsRefPtr<ContainerLayer> root = aBuilder->LayerBuilder()->
601 : BuildContainerLayerFor(aBuilder, layerManager, aForFrame, nsnull, *this,
602 0 : containerParameters, nsnull);
603 0 : if (!root)
604 : return;
605 : // Root is being scaled up by the X/Y resolution. Scale it back down.
606 0 : gfx3DMatrix rootTransform = root->GetTransform()*
607 : gfx3DMatrix::ScalingMatrix(1.0f/containerParameters.mXScale,
608 0 : 1.0f/containerParameters.mYScale, 1.0f);
609 0 : root->SetTransform(rootTransform);
610 :
611 0 : ViewID id = presContext->IsRootContentDocument() ? FrameMetrics::ROOT_SCROLL_ID
612 0 : : FrameMetrics::NULL_SCROLL_ID;
613 :
614 0 : nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
615 0 : nsRect displayport;
616 0 : bool usingDisplayport = false;
617 0 : if (rootScrollFrame) {
618 0 : nsIContent* content = rootScrollFrame->GetContent();
619 0 : if (content) {
620 0 : usingDisplayport = nsLayoutUtils::GetDisplayPort(content, &displayport);
621 : }
622 : }
623 : RecordFrameMetrics(aForFrame, rootScrollFrame,
624 : root, mVisibleRect, mVisibleRect,
625 : (usingDisplayport ? &displayport : nsnull), id,
626 0 : containerParameters);
627 0 : if (usingDisplayport &&
628 0 : !(root->GetContentFlags() & Layer::CONTENT_OPAQUE)) {
629 : // See bug 693938, attachment 567017
630 0 : NS_WARNING("We don't support transparent content with displayports, force it to be opqaue");
631 0 : root->SetContentFlags(Layer::CONTENT_OPAQUE);
632 : }
633 :
634 0 : layerManager->SetRoot(root);
635 0 : aBuilder->LayerBuilder()->WillEndTransaction(layerManager);
636 0 : layerManager->EndTransaction(FrameLayerBuilder::DrawThebesLayer,
637 0 : aBuilder);
638 0 : aBuilder->LayerBuilder()->DidEndTransaction(layerManager);
639 :
640 0 : if (aFlags & PAINT_FLUSH_LAYERS) {
641 0 : FrameLayerBuilder::InvalidateAllLayers(layerManager);
642 : }
643 :
644 0 : nsCSSRendering::DidPaint();
645 : }
646 :
647 0 : PRUint32 nsDisplayList::Count() const {
648 0 : PRUint32 count = 0;
649 0 : for (nsDisplayItem* i = GetBottom(); i; i = i->GetAbove()) {
650 0 : ++count;
651 : }
652 0 : return count;
653 : }
654 :
655 0 : nsDisplayItem* nsDisplayList::RemoveBottom() {
656 0 : nsDisplayItem* item = mSentinel.mAbove;
657 0 : if (!item)
658 0 : return nsnull;
659 0 : mSentinel.mAbove = item->mAbove;
660 0 : if (item == mTop) {
661 : // must have been the only item
662 0 : mTop = &mSentinel;
663 : }
664 0 : item->mAbove = nsnull;
665 0 : return item;
666 : }
667 :
668 0 : void nsDisplayList::DeleteAll() {
669 : nsDisplayItem* item;
670 0 : while ((item = RemoveBottom()) != nsnull) {
671 0 : item->~nsDisplayItem();
672 : }
673 0 : }
674 :
675 : static bool
676 0 : GetMouseThrough(const nsIFrame* aFrame)
677 : {
678 0 : if (!aFrame->IsBoxFrame())
679 0 : return false;
680 :
681 0 : const nsIFrame* frame = aFrame;
682 0 : while (frame) {
683 0 : if (frame->GetStateBits() & NS_FRAME_MOUSE_THROUGH_ALWAYS) {
684 0 : return true;
685 0 : } else if (frame->GetStateBits() & NS_FRAME_MOUSE_THROUGH_NEVER) {
686 0 : return false;
687 : }
688 0 : frame = frame->GetParentBox();
689 : }
690 0 : return false;
691 : }
692 :
693 : // A list of frames, and their z depth. Used for sorting
694 : // the results of hit testing.
695 : struct FramesWithDepth
696 0 : {
697 0 : FramesWithDepth(float aDepth) :
698 0 : mDepth(aDepth)
699 0 : {}
700 :
701 0 : bool operator<(const FramesWithDepth& aOther) const {
702 0 : if (mDepth != aOther.mDepth) {
703 : // We want to sort so that the shallowest item (highest depth value) is first
704 0 : return mDepth > aOther.mDepth;
705 : }
706 0 : return this < &aOther;
707 : }
708 0 : bool operator==(const FramesWithDepth& aOther) const {
709 0 : return this == &aOther;
710 : }
711 :
712 : float mDepth;
713 : nsTArray<nsIFrame*> mFrames;
714 : };
715 :
716 : // Sort the frames by depth and then moves all the contained frames to the destination
717 0 : void FlushFramesArray(nsTArray<FramesWithDepth>& aSource, nsTArray<nsIFrame*>* aDest)
718 : {
719 0 : if (aSource.IsEmpty()) {
720 0 : return;
721 : }
722 0 : aSource.Sort();
723 0 : PRUint32 length = aSource.Length();
724 0 : for (PRUint32 i = 0; i < length; i++) {
725 0 : aDest->MoveElementsFrom(aSource[i].mFrames);
726 : }
727 0 : aSource.Clear();
728 : }
729 :
730 0 : void nsDisplayList::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
731 : nsDisplayItem::HitTestState* aState,
732 : nsTArray<nsIFrame*> *aOutFrames) const {
733 0 : PRInt32 itemBufferStart = aState->mItemBuffer.Length();
734 : nsDisplayItem* item;
735 0 : for (item = GetBottom(); item; item = item->GetAbove()) {
736 0 : aState->mItemBuffer.AppendElement(item);
737 : }
738 0 : nsAutoTArray<FramesWithDepth, 16> temp;
739 0 : for (PRInt32 i = aState->mItemBuffer.Length() - 1; i >= itemBufferStart; --i) {
740 : // Pop element off the end of the buffer. We want to shorten the buffer
741 : // so that recursive calls to HitTest have more buffer space.
742 0 : item = aState->mItemBuffer[i];
743 0 : aState->mItemBuffer.SetLength(i);
744 :
745 0 : if (aRect.Intersects(item->GetBounds(aBuilder))) {
746 0 : nsAutoTArray<nsIFrame*, 16> outFrames;
747 0 : item->HitTest(aBuilder, aRect, aState, &outFrames);
748 :
749 : // For 3d transforms with preserve-3d we add hit frames into the temp list
750 : // so we can sort them later, otherwise we add them directly to the output list.
751 0 : nsTArray<nsIFrame*> *writeFrames = aOutFrames;
752 0 : if (item->GetType() == nsDisplayItem::TYPE_TRANSFORM &&
753 0 : item->GetUnderlyingFrame()->Preserves3D()) {
754 0 : if (outFrames.Length()) {
755 0 : nsDisplayTransform *transform = static_cast<nsDisplayTransform*>(item);
756 0 : nsPoint point = aRect.TopLeft();
757 : // A 1x1 rect means a point, otherwise use the center of the rect
758 0 : if (aRect.width != 1 || aRect.height != 1) {
759 0 : point = aRect.Center();
760 : }
761 0 : temp.AppendElement(FramesWithDepth(transform->GetHitDepthAtPoint(point)));
762 0 : writeFrames = &temp[temp.Length() - 1].mFrames;
763 : }
764 : } else {
765 : // We may have just finished a run of consecutive preserve-3d transforms,
766 : // so flush these into the destination array before processing our frame list.
767 0 : FlushFramesArray(temp, aOutFrames);
768 : }
769 :
770 0 : for (PRUint32 j = 0; j < outFrames.Length(); j++) {
771 0 : nsIFrame *f = outFrames.ElementAt(j);
772 : // Handle the XUL 'mousethrough' feature and 'pointer-events'.
773 0 : if (!GetMouseThrough(f) &&
774 0 : f->GetStyleVisibility()->mPointerEvents != NS_STYLE_POINTER_EVENTS_NONE) {
775 0 : writeFrames->AppendElement(f);
776 : }
777 : }
778 : }
779 : }
780 : // Clear any remaining preserve-3d transforms.
781 0 : FlushFramesArray(temp, aOutFrames);
782 0 : NS_ASSERTION(aState->mItemBuffer.Length() == PRUint32(itemBufferStart),
783 : "How did we forget to pop some elements?");
784 0 : }
785 :
786 0 : static void Sort(nsDisplayList* aList, PRInt32 aCount, nsDisplayList::SortLEQ aCmp,
787 : void* aClosure) {
788 0 : if (aCount < 2)
789 0 : return;
790 :
791 0 : nsDisplayList list1;
792 0 : nsDisplayList list2;
793 : int i;
794 0 : PRInt32 half = aCount/2;
795 0 : bool sorted = true;
796 0 : nsDisplayItem* prev = nsnull;
797 0 : for (i = 0; i < aCount; ++i) {
798 0 : nsDisplayItem* item = aList->RemoveBottom();
799 0 : (i < half ? &list1 : &list2)->AppendToTop(item);
800 0 : if (sorted && prev && !aCmp(prev, item, aClosure)) {
801 0 : sorted = false;
802 : }
803 0 : prev = item;
804 : }
805 0 : if (sorted) {
806 0 : aList->AppendToTop(&list1);
807 0 : aList->AppendToTop(&list2);
808 : return;
809 : }
810 :
811 0 : Sort(&list1, half, aCmp, aClosure);
812 0 : Sort(&list2, aCount - half, aCmp, aClosure);
813 :
814 0 : for (i = 0; i < aCount; ++i) {
815 0 : if (list1.GetBottom() &&
816 0 : (!list2.GetBottom() ||
817 0 : aCmp(list1.GetBottom(), list2.GetBottom(), aClosure))) {
818 0 : aList->AppendToTop(list1.RemoveBottom());
819 : } else {
820 0 : aList->AppendToTop(list2.RemoveBottom());
821 : }
822 : }
823 : }
824 :
825 0 : static bool IsContentLEQ(nsDisplayItem* aItem1, nsDisplayItem* aItem2,
826 : void* aClosure) {
827 : // These GetUnderlyingFrame calls return non-null because we're only used
828 : // in sorting
829 : return nsLayoutUtils::CompareTreePosition(
830 : aItem1->GetUnderlyingFrame()->GetContent(),
831 : aItem2->GetUnderlyingFrame()->GetContent(),
832 0 : static_cast<nsIContent*>(aClosure)) <= 0;
833 : }
834 :
835 0 : static bool IsZOrderLEQ(nsDisplayItem* aItem1, nsDisplayItem* aItem2,
836 : void* aClosure) {
837 : // These GetUnderlyingFrame calls return non-null because we're only used
838 : // in sorting. Note that we can't just take the difference of the two
839 : // z-indices here, because that might overflow a 32-bit int.
840 0 : PRInt32 index1 = nsLayoutUtils::GetZIndex(aItem1->GetUnderlyingFrame());
841 0 : PRInt32 index2 = nsLayoutUtils::GetZIndex(aItem2->GetUnderlyingFrame());
842 0 : if (index1 == index2)
843 0 : return IsContentLEQ(aItem1, aItem2, aClosure);
844 0 : return index1 < index2;
845 : }
846 :
847 0 : void nsDisplayList::ExplodeAnonymousChildLists(nsDisplayListBuilder* aBuilder) {
848 : // See if there's anything to do
849 0 : bool anyAnonymousItems = false;
850 : nsDisplayItem* i;
851 0 : for (i = GetBottom(); i != nsnull; i = i->GetAbove()) {
852 0 : if (!i->GetUnderlyingFrame()) {
853 0 : anyAnonymousItems = true;
854 0 : break;
855 : }
856 : }
857 0 : if (!anyAnonymousItems)
858 0 : return;
859 :
860 0 : nsDisplayList tmp;
861 0 : while ((i = RemoveBottom()) != nsnull) {
862 0 : if (i->GetUnderlyingFrame()) {
863 0 : tmp.AppendToTop(i);
864 : } else {
865 0 : nsDisplayList* list = i->GetList();
866 0 : NS_ASSERTION(list, "leaf items can't be anonymous");
867 0 : list->ExplodeAnonymousChildLists(aBuilder);
868 : nsDisplayItem* j;
869 0 : while ((j = list->RemoveBottom()) != nsnull) {
870 : tmp.AppendToTop(static_cast<nsDisplayWrapList*>(i)->
871 0 : WrapWithClone(aBuilder, j));
872 : }
873 0 : i->~nsDisplayItem();
874 : }
875 : }
876 :
877 0 : AppendToTop(&tmp);
878 : }
879 :
880 0 : void nsDisplayList::SortByZOrder(nsDisplayListBuilder* aBuilder,
881 : nsIContent* aCommonAncestor) {
882 0 : Sort(aBuilder, IsZOrderLEQ, aCommonAncestor);
883 0 : }
884 :
885 0 : void nsDisplayList::SortByContentOrder(nsDisplayListBuilder* aBuilder,
886 : nsIContent* aCommonAncestor) {
887 0 : Sort(aBuilder, IsContentLEQ, aCommonAncestor);
888 0 : }
889 :
890 0 : void nsDisplayList::Sort(nsDisplayListBuilder* aBuilder,
891 : SortLEQ aCmp, void* aClosure) {
892 0 : ExplodeAnonymousChildLists(aBuilder);
893 0 : ::Sort(this, Count(), aCmp, aClosure);
894 0 : }
895 :
896 0 : bool nsDisplayItem::RecomputeVisibility(nsDisplayListBuilder* aBuilder,
897 : nsRegion* aVisibleRegion) {
898 0 : nsRect bounds = GetBounds(aBuilder);
899 :
900 0 : nsRegion itemVisible;
901 0 : if (ForceVisiblityForFixedItem(aBuilder, this)) {
902 0 : itemVisible.And(GetDisplayPortBounds(aBuilder, this), bounds);
903 : } else {
904 0 : itemVisible.And(*aVisibleRegion, bounds);
905 : }
906 0 : mVisibleRect = itemVisible.GetBounds();
907 :
908 : // When we recompute visibility within layers we don't need to
909 : // expand the visible region for content behind plugins (the plugin
910 : // is not in the layer).
911 0 : if (!ComputeVisibility(aBuilder, aVisibleRegion, nsRect()))
912 0 : return false;
913 :
914 : bool forceTransparentBackground;
915 0 : nsRegion opaque = TreatAsOpaque(this, aBuilder, &forceTransparentBackground);
916 0 : aBuilder->SubtractFromVisibleRegion(aVisibleRegion, opaque);
917 0 : return true;
918 : }
919 :
920 : // Note that even if the rectangle we draw and snap is smaller than aRect,
921 : // it's OK to call this to get a bounding rect for what we'll draw, because
922 : // snapping a rectangle which is contained in R always gives you a
923 : // rectangle which is contained in the snapped R.
924 : static nsRect
925 0 : SnapBounds(bool aSnappingEnabled, nsPresContext* aPresContext,
926 : const nsRect& aRect) {
927 0 : nsRect r = aRect;
928 0 : if (aSnappingEnabled) {
929 0 : nscoord appUnitsPerDevPixel = aPresContext->AppUnitsPerDevPixel();
930 0 : r = r.ToNearestPixels(appUnitsPerDevPixel).ToAppUnits(appUnitsPerDevPixel);
931 : }
932 : return r;
933 : }
934 :
935 : nsRect
936 0 : nsDisplaySolidColor::GetBounds(nsDisplayListBuilder* aBuilder)
937 : {
938 0 : nsPresContext* presContext = mFrame->PresContext();
939 0 : return SnapBounds(mSnappingEnabled, presContext, mBounds);
940 : }
941 :
942 : void
943 0 : nsDisplaySolidColor::Paint(nsDisplayListBuilder* aBuilder,
944 : nsRenderingContext* aCtx)
945 : {
946 0 : aCtx->SetColor(mColor);
947 0 : aCtx->FillRect(mVisibleRect);
948 0 : }
949 :
950 : static void
951 0 : RegisterThemeGeometry(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
952 : {
953 0 : nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(aFrame);
954 :
955 0 : for (nsIFrame* f = aFrame; f; f = f->GetParent()) {
956 : // Bail out if we're in a transformed subtree
957 0 : if (f->IsTransformed())
958 0 : return;
959 : // Bail out if we're not in the displayRoot's document
960 0 : if (!f->GetParent() && f != displayRoot)
961 0 : return;
962 : }
963 :
964 0 : nsRect borderBox(aFrame->GetOffsetTo(displayRoot), aFrame->GetSize());
965 0 : aBuilder->RegisterThemeGeometry(aFrame->GetStyleDisplay()->mAppearance,
966 0 : borderBox.ToNearestPixels(aFrame->PresContext()->AppUnitsPerDevPixel()));
967 : }
968 :
969 0 : nsDisplayBackground::nsDisplayBackground(nsDisplayListBuilder* aBuilder,
970 : nsIFrame* aFrame)
971 : : nsDisplayItem(aBuilder, aFrame),
972 0 : mSnappingEnabled(aBuilder->IsSnappingEnabled() && !aBuilder->IsInTransform())
973 : {
974 0 : MOZ_COUNT_CTOR(nsDisplayBackground);
975 0 : const nsStyleDisplay* disp = mFrame->GetStyleDisplay();
976 0 : mIsThemed = mFrame->IsThemed(disp, &mThemeTransparency);
977 :
978 0 : if (mIsThemed) {
979 : // Perform necessary RegisterThemeGeometry
980 0 : if (disp->mAppearance == NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR ||
981 : disp->mAppearance == NS_THEME_TOOLBAR) {
982 0 : RegisterThemeGeometry(aBuilder, aFrame);
983 : }
984 : } else {
985 : // Set HasFixedItems if we construct a background-attachment:fixed item
986 0 : nsPresContext* presContext = mFrame->PresContext();
987 : nsStyleContext* bgSC;
988 0 : bool hasBG = nsCSSRendering::FindBackground(presContext, mFrame, &bgSC);
989 0 : if (hasBG && bgSC->GetStyleBackground()->HasFixedBackground()) {
990 0 : aBuilder->SetHasFixedItems();
991 : }
992 : }
993 0 : }
994 :
995 : // Helper for RoundedRectIntersectsRect.
996 : static bool
997 0 : CheckCorner(nscoord aXOffset, nscoord aYOffset,
998 : nscoord aXRadius, nscoord aYRadius)
999 : {
1000 0 : NS_ABORT_IF_FALSE(aXOffset > 0 && aYOffset > 0,
1001 : "must not pass nonpositives to CheckCorner");
1002 0 : NS_ABORT_IF_FALSE(aXRadius >= 0 && aYRadius >= 0,
1003 : "must not pass negatives to CheckCorner");
1004 :
1005 : // Avoid floating point math unless we're either (1) within the
1006 : // quarter-ellipse area at the rounded corner or (2) outside the
1007 : // rounding.
1008 0 : if (aXOffset >= aXRadius || aYOffset >= aYRadius)
1009 0 : return true;
1010 :
1011 : // Convert coordinates to a unit circle with (0,0) as the center of
1012 : // curvature, and see if we're inside the circle or outside.
1013 0 : float scaledX = float(aXRadius - aXOffset) / float(aXRadius);
1014 0 : float scaledY = float(aYRadius - aYOffset) / float(aYRadius);
1015 0 : return scaledX * scaledX + scaledY * scaledY < 1.0f;
1016 : }
1017 :
1018 :
1019 : /**
1020 : * Return whether any part of aTestRect is inside of the rounded
1021 : * rectangle formed by aBounds and aRadii (which are indexed by the
1022 : * NS_CORNER_* constants in nsStyleConsts.h).
1023 : *
1024 : * See also RoundedRectContainsRect.
1025 : */
1026 : static bool
1027 0 : RoundedRectIntersectsRect(const nsRect& aRoundedRect, nscoord aRadii[8],
1028 : const nsRect& aTestRect)
1029 : {
1030 0 : NS_ABORT_IF_FALSE(aTestRect.Intersects(aRoundedRect),
1031 : "we should already have tested basic rect intersection");
1032 :
1033 : // distances from this edge of aRoundedRect to opposite edge of aTestRect,
1034 : // which we know are positive due to the Intersects check above.
1035 0 : nsMargin insets;
1036 0 : insets.top = aTestRect.YMost() - aRoundedRect.y;
1037 0 : insets.right = aRoundedRect.XMost() - aTestRect.x;
1038 0 : insets.bottom = aRoundedRect.YMost() - aTestRect.y;
1039 0 : insets.left = aTestRect.XMost() - aRoundedRect.x;
1040 :
1041 : // Check whether the bottom-right corner of aTestRect is inside the
1042 : // top left corner of aBounds when rounded by aRadii, etc. If any
1043 : // corner is not, then fail; otherwise succeed.
1044 : return CheckCorner(insets.left, insets.top,
1045 : aRadii[NS_CORNER_TOP_LEFT_X],
1046 0 : aRadii[NS_CORNER_TOP_LEFT_Y]) &&
1047 : CheckCorner(insets.right, insets.top,
1048 0 : aRadii[NS_CORNER_TOP_RIGHT_X],
1049 0 : aRadii[NS_CORNER_TOP_RIGHT_Y]) &&
1050 : CheckCorner(insets.right, insets.bottom,
1051 0 : aRadii[NS_CORNER_BOTTOM_RIGHT_X],
1052 0 : aRadii[NS_CORNER_BOTTOM_RIGHT_Y]) &&
1053 : CheckCorner(insets.left, insets.bottom,
1054 0 : aRadii[NS_CORNER_BOTTOM_LEFT_X],
1055 0 : aRadii[NS_CORNER_BOTTOM_LEFT_Y]);
1056 : }
1057 :
1058 : // Check that the rounded border of aFrame, added to aToReferenceFrame,
1059 : // intersects aRect. Assumes that the unrounded border has already
1060 : // been checked for intersection.
1061 : static bool
1062 0 : RoundedBorderIntersectsRect(nsIFrame* aFrame,
1063 : const nsPoint& aFrameToReferenceFrame,
1064 : const nsRect& aTestRect)
1065 : {
1066 0 : if (!nsRect(aFrameToReferenceFrame, aFrame->GetSize()).Intersects(aTestRect))
1067 0 : return false;
1068 :
1069 : nscoord radii[8];
1070 0 : return !aFrame->GetBorderRadii(radii) ||
1071 : RoundedRectIntersectsRect(nsRect(aFrameToReferenceFrame,
1072 0 : aFrame->GetSize()),
1073 0 : radii, aTestRect);
1074 : }
1075 :
1076 : // Returns TRUE if aContainedRect is guaranteed to be contained in
1077 : // the rounded rect defined by aRoundedRect and aRadii. Complex cases are
1078 : // handled conservatively by returning FALSE in some situations where
1079 : // a more thorough analysis could return TRUE.
1080 : //
1081 : // See also RoundedRectIntersectsRect.
1082 0 : static bool RoundedRectContainsRect(const nsRect& aRoundedRect,
1083 : const nscoord aRadii[8],
1084 : const nsRect& aContainedRect) {
1085 0 : nsRegion rgn = nsLayoutUtils::RoundedRectIntersectRect(aRoundedRect, aRadii, aContainedRect);
1086 0 : return rgn.Contains(aContainedRect);
1087 : }
1088 :
1089 : void
1090 0 : nsDisplayBackground::HitTest(nsDisplayListBuilder* aBuilder,
1091 : const nsRect& aRect,
1092 : HitTestState* aState,
1093 : nsTArray<nsIFrame*> *aOutFrames)
1094 : {
1095 0 : if (mIsThemed) {
1096 : // For theme backgrounds, assume that any point in our border rect is a hit.
1097 0 : if (!nsRect(ToReferenceFrame(), mFrame->GetSize()).Intersects(aRect))
1098 0 : return;
1099 : } else {
1100 0 : if (!RoundedBorderIntersectsRect(mFrame, ToReferenceFrame(), aRect)) {
1101 : // aRect doesn't intersect our border-radius curve.
1102 0 : return;
1103 : }
1104 : }
1105 :
1106 0 : aOutFrames->AppendElement(mFrame);
1107 : }
1108 :
1109 : bool
1110 0 : nsDisplayBackground::ComputeVisibility(nsDisplayListBuilder* aBuilder,
1111 : nsRegion* aVisibleRegion,
1112 : const nsRect& aAllowVisibleRegionExpansion)
1113 : {
1114 0 : if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
1115 0 : aAllowVisibleRegionExpansion)) {
1116 0 : return false;
1117 : }
1118 :
1119 : // Return false if the background was propagated away from this
1120 : // frame. We don't want this display item to show up and confuse
1121 : // anything.
1122 : nsStyleContext* bgSC;
1123 : return mIsThemed ||
1124 0 : nsCSSRendering::FindBackground(mFrame->PresContext(), mFrame, &bgSC);
1125 : }
1126 :
1127 : nsRegion
1128 0 : nsDisplayBackground::GetInsideClipRegion(nsPresContext* aPresContext,
1129 : PRUint8 aClip, const nsRect& aRect)
1130 : {
1131 0 : nsRegion result;
1132 0 : if (aRect.IsEmpty())
1133 0 : return result;
1134 :
1135 : nscoord radii[8];
1136 0 : nsRect clipRect;
1137 : bool haveRadii;
1138 0 : switch (aClip) {
1139 : case NS_STYLE_BG_CLIP_BORDER:
1140 0 : haveRadii = mFrame->GetBorderRadii(radii);
1141 0 : clipRect = nsRect(ToReferenceFrame(), mFrame->GetSize());
1142 0 : break;
1143 : case NS_STYLE_BG_CLIP_PADDING:
1144 0 : haveRadii = mFrame->GetPaddingBoxBorderRadii(radii);
1145 0 : clipRect = mFrame->GetPaddingRect() - mFrame->GetPosition() + ToReferenceFrame();
1146 0 : break;
1147 : case NS_STYLE_BG_CLIP_CONTENT:
1148 0 : haveRadii = mFrame->GetContentBoxBorderRadii(radii);
1149 0 : clipRect = mFrame->GetContentRect() - mFrame->GetPosition() + ToReferenceFrame();
1150 0 : break;
1151 : default:
1152 0 : NS_NOTREACHED("Unknown clip type");
1153 : return result;
1154 : }
1155 :
1156 0 : nsRect inputRect = SnapBounds(mSnappingEnabled, aPresContext, aRect);
1157 0 : clipRect = SnapBounds(mSnappingEnabled, aPresContext, clipRect);
1158 :
1159 0 : if (haveRadii) {
1160 0 : result = nsLayoutUtils::RoundedRectIntersectRect(clipRect, radii, inputRect);
1161 : } else {
1162 0 : nsRect r;
1163 0 : r.IntersectRect(clipRect, inputRect);
1164 0 : result = r;
1165 : }
1166 : return result;
1167 : }
1168 :
1169 : nsRegion
1170 0 : nsDisplayBackground::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
1171 : bool* aForceTransparentSurface) {
1172 0 : nsRegion result;
1173 0 : if (aForceTransparentSurface) {
1174 0 : *aForceTransparentSurface = false;
1175 : }
1176 : // theme background overrides any other background
1177 0 : if (mIsThemed) {
1178 0 : if (aForceTransparentSurface) {
1179 0 : const nsStyleDisplay* disp = mFrame->GetStyleDisplay();
1180 : *aForceTransparentSurface = disp->mAppearance == NS_THEME_WIN_BORDERLESS_GLASS ||
1181 0 : disp->mAppearance == NS_THEME_WIN_GLASS;
1182 : }
1183 0 : if (mThemeTransparency == nsITheme::eOpaque) {
1184 0 : result = GetBounds(aBuilder);
1185 : }
1186 0 : return result;
1187 : }
1188 :
1189 : nsStyleContext* bgSC;
1190 0 : nsPresContext* presContext = mFrame->PresContext();
1191 0 : if (!nsCSSRendering::FindBackground(mFrame->PresContext(), mFrame, &bgSC))
1192 0 : return result;
1193 0 : const nsStyleBackground* bg = bgSC->GetStyleBackground();
1194 0 : const nsStyleBackground::Layer& bottomLayer = bg->BottomLayer();
1195 :
1196 0 : nsRect borderBox = nsRect(ToReferenceFrame(), mFrame->GetSize());
1197 0 : if (NS_GET_A(bg->mBackgroundColor) == 255 &&
1198 0 : !nsCSSRendering::IsCanvasFrame(mFrame)) {
1199 0 : result = GetInsideClipRegion(presContext, bottomLayer.mClip, borderBox);
1200 : }
1201 :
1202 : // For policies other than EACH_BOX, don't try to optimize here, since
1203 : // this could easily lead to O(N^2) behavior inside InlineBackgroundData,
1204 : // which expects frames to be sent to it in content order, not reverse
1205 : // content order which we'll produce here.
1206 : // Of course, if there's only one frame in the flow, it doesn't matter.
1207 0 : if (bg->mBackgroundInlinePolicy == NS_STYLE_BG_INLINE_POLICY_EACH_BOX ||
1208 0 : (!mFrame->GetPrevContinuation() && !mFrame->GetNextContinuation())) {
1209 0 : NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
1210 0 : const nsStyleBackground::Layer& layer = bg->mLayers[i];
1211 0 : if (layer.mImage.IsOpaque()) {
1212 : nsRect r = nsCSSRendering::GetBackgroundLayerRect(presContext, mFrame,
1213 0 : borderBox, *bg, layer);
1214 0 : result.Or(result, GetInsideClipRegion(presContext, layer.mClip, r));
1215 : }
1216 : }
1217 : }
1218 :
1219 : return result;
1220 : }
1221 :
1222 : bool
1223 0 : nsDisplayBackground::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) {
1224 : // theme background overrides any other background
1225 0 : if (mIsThemed) {
1226 0 : const nsStyleDisplay* disp = mFrame->GetStyleDisplay();
1227 0 : if (disp->mAppearance == NS_THEME_WIN_BORDERLESS_GLASS ||
1228 : disp->mAppearance == NS_THEME_WIN_GLASS) {
1229 0 : *aColor = NS_RGBA(0,0,0,0);
1230 0 : return true;
1231 : }
1232 0 : return false;
1233 : }
1234 :
1235 : nsStyleContext *bgSC;
1236 : bool hasBG =
1237 0 : nsCSSRendering::FindBackground(mFrame->PresContext(), mFrame, &bgSC);
1238 0 : if (!hasBG) {
1239 0 : *aColor = NS_RGBA(0,0,0,0);
1240 0 : return true;
1241 : }
1242 0 : const nsStyleBackground* bg = bgSC->GetStyleBackground();
1243 0 : if (bg->BottomLayer().mImage.IsEmpty() &&
1244 : bg->mImageCount == 1 &&
1245 0 : !nsLayoutUtils::HasNonZeroCorner(mFrame->GetStyleBorder()->mBorderRadius) &&
1246 0 : bg->BottomLayer().mClip == NS_STYLE_BG_CLIP_BORDER) {
1247 : // Canvas frames don't actually render their background color, since that
1248 : // gets propagated to the solid color of the viewport
1249 : // (see nsCSSRendering::PaintBackgroundWithSC)
1250 0 : *aColor = nsCSSRendering::IsCanvasFrame(mFrame) ? NS_RGBA(0,0,0,0)
1251 0 : : bg->mBackgroundColor;
1252 0 : return true;
1253 : }
1254 0 : return false;
1255 : }
1256 :
1257 : bool
1258 0 : nsDisplayBackground::IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
1259 : nsIFrame* aFrame)
1260 : {
1261 : // theme background overrides any other background and is never fixed
1262 0 : if (mIsThemed)
1263 0 : return false;
1264 :
1265 0 : nsPresContext* presContext = mFrame->PresContext();
1266 : nsStyleContext *bgSC;
1267 : bool hasBG =
1268 0 : nsCSSRendering::FindBackground(presContext, mFrame, &bgSC);
1269 0 : if (!hasBG)
1270 0 : return false;
1271 0 : const nsStyleBackground* bg = bgSC->GetStyleBackground();
1272 0 : if (!bg->HasFixedBackground())
1273 0 : return false;
1274 :
1275 : // If aFrame is mFrame or an ancestor in this document, and aFrame is
1276 : // not the viewport frame, then moving aFrame will move mFrame
1277 : // relative to the viewport, so our fixed-pos background will change.
1278 0 : return aFrame->GetParent() &&
1279 : (aFrame == mFrame ||
1280 0 : nsLayoutUtils::IsProperAncestorFrame(aFrame, mFrame));
1281 : }
1282 :
1283 : bool
1284 0 : nsDisplayBackground::ShouldFixToViewport(nsDisplayListBuilder* aBuilder)
1285 : {
1286 0 : if (mIsThemed)
1287 0 : return false;
1288 :
1289 0 : nsPresContext* presContext = mFrame->PresContext();
1290 : nsStyleContext* bgSC;
1291 : bool hasBG =
1292 0 : nsCSSRendering::FindBackground(presContext, mFrame, &bgSC);
1293 0 : if (!hasBG)
1294 0 : return false;
1295 :
1296 0 : const nsStyleBackground* bg = bgSC->GetStyleBackground();
1297 0 : if (!bg->HasFixedBackground())
1298 0 : return false;
1299 :
1300 0 : NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
1301 0 : const nsStyleBackground::Layer& layer = bg->mLayers[i];
1302 0 : if (layer.mAttachment != NS_STYLE_BG_ATTACHMENT_FIXED &&
1303 0 : !layer.mImage.IsEmpty()) {
1304 0 : return false;
1305 : }
1306 0 : if (layer.mClip != NS_STYLE_BG_CLIP_BORDER)
1307 0 : return false;
1308 : }
1309 :
1310 0 : if (nsLayoutUtils::HasNonZeroCorner(mFrame->GetStyleBorder()->mBorderRadius))
1311 0 : return false;
1312 :
1313 0 : nsRect bounds = GetBounds(aBuilder);
1314 0 : nsIFrame* rootScrollFrame = presContext->PresShell()->GetRootScrollFrame();
1315 0 : if (!rootScrollFrame)
1316 0 : return false;
1317 0 : nsIScrollableFrame* scrollable = do_QueryFrame(rootScrollFrame);
1318 0 : nsRect scrollport = scrollable->GetScrollPortRect() +
1319 0 : aBuilder->ToReferenceFrame(rootScrollFrame);
1320 0 : return bounds.Contains(scrollport);
1321 : }
1322 :
1323 : void
1324 0 : nsDisplayBackground::Paint(nsDisplayListBuilder* aBuilder,
1325 : nsRenderingContext* aCtx) {
1326 0 : nsPoint offset = ToReferenceFrame();
1327 0 : PRUint32 flags = aBuilder->GetBackgroundPaintFlags();
1328 0 : nsDisplayItem* nextItem = GetAbove();
1329 0 : if (nextItem && nextItem->GetUnderlyingFrame() == mFrame &&
1330 0 : nextItem->GetType() == TYPE_BORDER) {
1331 0 : flags |= nsCSSRendering::PAINTBG_WILL_PAINT_BORDER;
1332 : }
1333 : nsCSSRendering::PaintBackground(mFrame->PresContext(), *aCtx, mFrame,
1334 : mVisibleRect,
1335 0 : nsRect(offset, mFrame->GetSize()),
1336 0 : flags);
1337 0 : }
1338 :
1339 : nsRect
1340 0 : nsDisplayBackground::GetBounds(nsDisplayListBuilder* aBuilder) {
1341 0 : nsRect r(nsPoint(0,0), mFrame->GetSize());
1342 0 : nsPresContext* presContext = mFrame->PresContext();
1343 :
1344 0 : if (mIsThemed) {
1345 0 : presContext->GetTheme()->
1346 : GetWidgetOverflow(presContext->DeviceContext(), mFrame,
1347 0 : mFrame->GetStyleDisplay()->mAppearance, &r);
1348 : }
1349 :
1350 0 : return SnapBounds(mSnappingEnabled, presContext, r + ToReferenceFrame());
1351 : }
1352 :
1353 : nsRect
1354 0 : nsDisplayOutline::GetBounds(nsDisplayListBuilder* aBuilder) {
1355 0 : return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
1356 : }
1357 :
1358 : void
1359 0 : nsDisplayOutline::Paint(nsDisplayListBuilder* aBuilder,
1360 : nsRenderingContext* aCtx) {
1361 : // TODO join outlines together
1362 0 : nsPoint offset = ToReferenceFrame();
1363 : nsCSSRendering::PaintOutline(mFrame->PresContext(), *aCtx, mFrame,
1364 : mVisibleRect,
1365 0 : nsRect(offset, mFrame->GetSize()),
1366 0 : mFrame->GetStyleContext());
1367 0 : }
1368 :
1369 : bool
1370 0 : nsDisplayOutline::ComputeVisibility(nsDisplayListBuilder* aBuilder,
1371 : nsRegion* aVisibleRegion,
1372 : const nsRect& aAllowVisibleRegionExpansion) {
1373 0 : if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
1374 0 : aAllowVisibleRegionExpansion)) {
1375 0 : return false;
1376 : }
1377 :
1378 0 : const nsStyleOutline* outline = mFrame->GetStyleOutline();
1379 0 : nsRect borderBox(ToReferenceFrame(), mFrame->GetSize());
1380 0 : if (borderBox.Contains(aVisibleRegion->GetBounds()) &&
1381 0 : !nsLayoutUtils::HasNonZeroCorner(outline->mOutlineRadius)) {
1382 0 : if (outline->mOutlineOffset >= 0) {
1383 : // the visible region is entirely inside the border-rect, and the outline
1384 : // isn't rendered inside the border-rect, so the outline is not visible
1385 0 : return false;
1386 : }
1387 : }
1388 :
1389 0 : return true;
1390 : }
1391 :
1392 : void
1393 0 : nsDisplayEventReceiver::HitTest(nsDisplayListBuilder* aBuilder,
1394 : const nsRect& aRect,
1395 : HitTestState* aState,
1396 : nsTArray<nsIFrame*> *aOutFrames)
1397 : {
1398 0 : if (!RoundedBorderIntersectsRect(mFrame, ToReferenceFrame(), aRect)) {
1399 : // aRect doesn't intersect our border-radius curve.
1400 0 : return;
1401 : }
1402 :
1403 0 : aOutFrames->AppendElement(mFrame);
1404 : }
1405 :
1406 : void
1407 0 : nsDisplayCaret::Paint(nsDisplayListBuilder* aBuilder,
1408 : nsRenderingContext* aCtx) {
1409 : // Note: Because we exist, we know that the caret is visible, so we don't
1410 : // need to check for the caret's visibility.
1411 0 : mCaret->PaintCaret(aBuilder, aCtx, mFrame, ToReferenceFrame());
1412 0 : }
1413 :
1414 : bool
1415 0 : nsDisplayBorder::ComputeVisibility(nsDisplayListBuilder* aBuilder,
1416 : nsRegion* aVisibleRegion,
1417 : const nsRect& aAllowVisibleRegionExpansion) {
1418 0 : if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
1419 0 : aAllowVisibleRegionExpansion)) {
1420 0 : return false;
1421 : }
1422 :
1423 0 : nsRect paddingRect = mFrame->GetPaddingRect() - mFrame->GetPosition() +
1424 0 : ToReferenceFrame();
1425 : const nsStyleBorder *styleBorder;
1426 0 : if (paddingRect.Contains(aVisibleRegion->GetBounds()) &&
1427 0 : !(styleBorder = mFrame->GetStyleBorder())->IsBorderImageLoaded() &&
1428 0 : !nsLayoutUtils::HasNonZeroCorner(styleBorder->mBorderRadius)) {
1429 : // the visible region is entirely inside the content rect, and no part
1430 : // of the border is rendered inside the content rect, so we are not
1431 : // visible
1432 : // Skip this if there's a border-image (which draws a background
1433 : // too) or if there is a border-radius (which makes the border draw
1434 : // further in).
1435 0 : return false;
1436 : }
1437 :
1438 0 : return true;
1439 : }
1440 :
1441 : void
1442 0 : nsDisplayBorder::Paint(nsDisplayListBuilder* aBuilder,
1443 : nsRenderingContext* aCtx) {
1444 0 : nsPoint offset = ToReferenceFrame();
1445 : nsCSSRendering::PaintBorder(mFrame->PresContext(), *aCtx, mFrame,
1446 : mVisibleRect,
1447 0 : nsRect(offset, mFrame->GetSize()),
1448 : mFrame->GetStyleContext(),
1449 0 : mFrame->GetSkipSides());
1450 0 : }
1451 :
1452 : nsRect
1453 0 : nsDisplayBorder::GetBounds(nsDisplayListBuilder* aBuilder)
1454 : {
1455 0 : nsRect borderBounds(ToReferenceFrame(), mFrame->GetSize());
1456 0 : borderBounds.Inflate(mFrame->GetStyleBorder()->GetImageOutset());
1457 0 : return SnapBounds(mSnappingEnabled, mFrame->PresContext(), borderBounds);
1458 : }
1459 :
1460 : // Given a region, compute a conservative approximation to it as a list
1461 : // of rectangles that aren't vertically adjacent (i.e., vertically
1462 : // adjacent or overlapping rectangles are combined).
1463 : // Right now this is only approximate, some vertically overlapping rectangles
1464 : // aren't guaranteed to be combined.
1465 : static void
1466 0 : ComputeDisjointRectangles(const nsRegion& aRegion,
1467 : nsTArray<nsRect>* aRects) {
1468 0 : nscoord accumulationMargin = nsPresContext::CSSPixelsToAppUnits(25);
1469 0 : nsRect accumulated;
1470 0 : nsRegionRectIterator iter(aRegion);
1471 0 : while (true) {
1472 0 : const nsRect* r = iter.Next();
1473 0 : if (r && !accumulated.IsEmpty() &&
1474 0 : accumulated.YMost() >= r->y - accumulationMargin) {
1475 0 : accumulated.UnionRect(accumulated, *r);
1476 0 : continue;
1477 : }
1478 :
1479 0 : if (!accumulated.IsEmpty()) {
1480 0 : aRects->AppendElement(accumulated);
1481 0 : accumulated.SetEmpty();
1482 : }
1483 :
1484 0 : if (!r)
1485 : break;
1486 :
1487 0 : accumulated = *r;
1488 : }
1489 0 : }
1490 :
1491 : void
1492 0 : nsDisplayBoxShadowOuter::Paint(nsDisplayListBuilder* aBuilder,
1493 : nsRenderingContext* aCtx) {
1494 0 : nsPoint offset = ToReferenceFrame();
1495 0 : nsRect borderRect = nsRect(offset, mFrame->GetSize());
1496 0 : nsPresContext* presContext = mFrame->PresContext();
1497 0 : nsAutoTArray<nsRect,10> rects;
1498 0 : ComputeDisjointRectangles(mVisibleRegion, &rects);
1499 :
1500 0 : for (PRUint32 i = 0; i < rects.Length(); ++i) {
1501 0 : aCtx->PushState();
1502 0 : aCtx->IntersectClip(rects[i]);
1503 : nsCSSRendering::PaintBoxShadowOuter(presContext, *aCtx, mFrame,
1504 0 : borderRect, rects[i]);
1505 0 : aCtx->PopState();
1506 : }
1507 0 : }
1508 :
1509 : nsRect
1510 0 : nsDisplayBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder) {
1511 0 : return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
1512 : }
1513 :
1514 : bool
1515 0 : nsDisplayBoxShadowOuter::ComputeVisibility(nsDisplayListBuilder* aBuilder,
1516 : nsRegion* aVisibleRegion,
1517 : const nsRect& aAllowVisibleRegionExpansion) {
1518 0 : if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
1519 0 : aAllowVisibleRegionExpansion)) {
1520 0 : return false;
1521 : }
1522 :
1523 : // Store the actual visible region
1524 0 : mVisibleRegion.And(*aVisibleRegion, mVisibleRect);
1525 :
1526 0 : nsPoint origin = ToReferenceFrame();
1527 0 : nsRect visibleBounds = aVisibleRegion->GetBounds();
1528 0 : nsRect frameRect(origin, mFrame->GetSize());
1529 0 : if (!frameRect.Contains(visibleBounds))
1530 0 : return true;
1531 :
1532 : // the visible region is entirely inside the border-rect, and box shadows
1533 : // never render within the border-rect (unless there's a border radius).
1534 : nscoord twipsRadii[8];
1535 0 : bool hasBorderRadii = mFrame->GetBorderRadii(twipsRadii);
1536 0 : if (!hasBorderRadii)
1537 0 : return false;
1538 :
1539 0 : return !RoundedRectContainsRect(frameRect, twipsRadii, visibleBounds);
1540 : }
1541 :
1542 : void
1543 0 : nsDisplayBoxShadowInner::Paint(nsDisplayListBuilder* aBuilder,
1544 : nsRenderingContext* aCtx) {
1545 0 : nsPoint offset = ToReferenceFrame();
1546 0 : nsRect borderRect = nsRect(offset, mFrame->GetSize());
1547 0 : nsPresContext* presContext = mFrame->PresContext();
1548 0 : nsAutoTArray<nsRect,10> rects;
1549 0 : ComputeDisjointRectangles(mVisibleRegion, &rects);
1550 :
1551 0 : for (PRUint32 i = 0; i < rects.Length(); ++i) {
1552 0 : aCtx->PushState();
1553 0 : aCtx->IntersectClip(rects[i]);
1554 : nsCSSRendering::PaintBoxShadowInner(presContext, *aCtx, mFrame,
1555 0 : borderRect, rects[i]);
1556 0 : aCtx->PopState();
1557 : }
1558 0 : }
1559 :
1560 : bool
1561 0 : nsDisplayBoxShadowInner::ComputeVisibility(nsDisplayListBuilder* aBuilder,
1562 : nsRegion* aVisibleRegion,
1563 : const nsRect& aAllowVisibleRegionExpansion) {
1564 0 : if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
1565 0 : aAllowVisibleRegionExpansion)) {
1566 0 : return false;
1567 : }
1568 :
1569 : // Store the actual visible region
1570 0 : mVisibleRegion.And(*aVisibleRegion, mVisibleRect);
1571 0 : return true;
1572 : }
1573 :
1574 0 : nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
1575 : nsIFrame* aFrame, nsDisplayList* aList)
1576 0 : : nsDisplayItem(aBuilder, aFrame) {
1577 0 : mList.AppendToTop(aList);
1578 0 : }
1579 :
1580 0 : nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
1581 : nsIFrame* aFrame, nsDisplayItem* aItem)
1582 0 : : nsDisplayItem(aBuilder, aFrame) {
1583 0 : mList.AppendToTop(aItem);
1584 0 : }
1585 :
1586 0 : nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
1587 : nsIFrame* aFrame)
1588 0 : : nsDisplayItem(aBuilder, aFrame) {
1589 0 : }
1590 :
1591 0 : nsDisplayWrapList::~nsDisplayWrapList() {
1592 0 : mList.DeleteAll();
1593 0 : }
1594 :
1595 : void
1596 0 : nsDisplayWrapList::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
1597 : HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {
1598 0 : mList.HitTest(aBuilder, aRect, aState, aOutFrames);
1599 0 : }
1600 :
1601 : nsRect
1602 0 : nsDisplayWrapList::GetBounds(nsDisplayListBuilder* aBuilder) {
1603 0 : return mList.GetBounds(aBuilder);
1604 : }
1605 :
1606 : bool
1607 0 : nsDisplayWrapList::ComputeVisibility(nsDisplayListBuilder* aBuilder,
1608 : nsRegion* aVisibleRegion,
1609 : const nsRect& aAllowVisibleRegionExpansion) {
1610 : return mList.ComputeVisibilityForSublist(aBuilder, aVisibleRegion,
1611 : mVisibleRect,
1612 0 : aAllowVisibleRegionExpansion);
1613 : }
1614 :
1615 : nsRegion
1616 0 : nsDisplayWrapList::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
1617 : bool* aForceTransparentSurface) {
1618 0 : if (aForceTransparentSurface) {
1619 0 : *aForceTransparentSurface = false;
1620 : }
1621 0 : nsRegion result;
1622 0 : if (mList.IsOpaque()) {
1623 0 : result = GetBounds(aBuilder);
1624 : }
1625 : return result;
1626 : }
1627 :
1628 0 : bool nsDisplayWrapList::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) {
1629 : // We could try to do something but let's conservatively just return false.
1630 0 : return false;
1631 : }
1632 :
1633 0 : bool nsDisplayWrapList::IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
1634 : nsIFrame* aFrame) {
1635 0 : NS_WARNING("nsDisplayWrapList::IsVaryingRelativeToMovingFrame called unexpectedly");
1636 : // We could try to do something but let's conservatively just return true.
1637 0 : return true;
1638 : }
1639 :
1640 0 : void nsDisplayWrapList::Paint(nsDisplayListBuilder* aBuilder,
1641 : nsRenderingContext* aCtx) {
1642 0 : NS_ERROR("nsDisplayWrapList should have been flattened away for painting");
1643 0 : }
1644 :
1645 0 : bool nsDisplayWrapList::ChildrenCanBeInactive(nsDisplayListBuilder* aBuilder,
1646 : LayerManager* aManager,
1647 : const nsDisplayList& aList,
1648 : nsIFrame* aActiveScrolledRoot) {
1649 0 : for (nsDisplayItem* i = aList.GetBottom(); i; i = i->GetAbove()) {
1650 0 : nsIFrame* f = i->GetUnderlyingFrame();
1651 0 : if (f) {
1652 : nsIFrame* activeScrolledRoot =
1653 0 : nsLayoutUtils::GetActiveScrolledRootFor(f, nsnull);
1654 0 : if (activeScrolledRoot != aActiveScrolledRoot)
1655 0 : return false;
1656 : }
1657 :
1658 0 : LayerState state = i->GetLayerState(aBuilder, aManager);
1659 0 : if (state == LAYER_ACTIVE)
1660 0 : return false;
1661 0 : if (state == LAYER_NONE) {
1662 0 : nsDisplayList* list = i->GetList();
1663 0 : if (list && !ChildrenCanBeInactive(aBuilder, aManager, *list, aActiveScrolledRoot))
1664 0 : return false;
1665 : }
1666 : }
1667 0 : return true;
1668 : }
1669 :
1670 0 : nsRect nsDisplayWrapList::GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder)
1671 : {
1672 0 : nsRect bounds;
1673 0 : for (nsDisplayItem* i = mList.GetBottom(); i; i = i->GetAbove()) {
1674 0 : bounds.UnionRect(bounds, i->GetComponentAlphaBounds(aBuilder));
1675 : }
1676 : return bounds;
1677 : }
1678 :
1679 : static nsresult
1680 0 : WrapDisplayList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
1681 : nsDisplayList* aList, nsDisplayWrapper* aWrapper) {
1682 0 : if (!aList->GetTop())
1683 0 : return NS_OK;
1684 0 : nsDisplayItem* item = aWrapper->WrapList(aBuilder, aFrame, aList);
1685 0 : if (!item)
1686 0 : return NS_ERROR_OUT_OF_MEMORY;
1687 : // aList was emptied
1688 0 : aList->AppendToTop(item);
1689 0 : return NS_OK;
1690 : }
1691 :
1692 : static nsresult
1693 0 : WrapEachDisplayItem(nsDisplayListBuilder* aBuilder,
1694 : nsDisplayList* aList, nsDisplayWrapper* aWrapper) {
1695 0 : nsDisplayList newList;
1696 : nsDisplayItem* item;
1697 0 : while ((item = aList->RemoveBottom())) {
1698 0 : item = aWrapper->WrapItem(aBuilder, item);
1699 0 : if (!item)
1700 0 : return NS_ERROR_OUT_OF_MEMORY;
1701 0 : newList.AppendToTop(item);
1702 : }
1703 : // aList was emptied
1704 0 : aList->AppendToTop(&newList);
1705 0 : return NS_OK;
1706 : }
1707 :
1708 0 : nsresult nsDisplayWrapper::WrapLists(nsDisplayListBuilder* aBuilder,
1709 : nsIFrame* aFrame, const nsDisplayListSet& aIn, const nsDisplayListSet& aOut)
1710 : {
1711 0 : nsresult rv = WrapListsInPlace(aBuilder, aFrame, aIn);
1712 0 : NS_ENSURE_SUCCESS(rv, rv);
1713 :
1714 0 : if (&aOut == &aIn)
1715 0 : return NS_OK;
1716 0 : aOut.BorderBackground()->AppendToTop(aIn.BorderBackground());
1717 0 : aOut.BlockBorderBackgrounds()->AppendToTop(aIn.BlockBorderBackgrounds());
1718 0 : aOut.Floats()->AppendToTop(aIn.Floats());
1719 0 : aOut.Content()->AppendToTop(aIn.Content());
1720 0 : aOut.PositionedDescendants()->AppendToTop(aIn.PositionedDescendants());
1721 0 : aOut.Outlines()->AppendToTop(aIn.Outlines());
1722 0 : return NS_OK;
1723 : }
1724 :
1725 0 : nsresult nsDisplayWrapper::WrapListsInPlace(nsDisplayListBuilder* aBuilder,
1726 : nsIFrame* aFrame, const nsDisplayListSet& aLists)
1727 : {
1728 : nsresult rv;
1729 0 : if (WrapBorderBackground()) {
1730 : // Our border-backgrounds are in-flow
1731 0 : rv = WrapDisplayList(aBuilder, aFrame, aLists.BorderBackground(), this);
1732 0 : NS_ENSURE_SUCCESS(rv, rv);
1733 : }
1734 : // Our block border-backgrounds are in-flow
1735 0 : rv = WrapDisplayList(aBuilder, aFrame, aLists.BlockBorderBackgrounds(), this);
1736 0 : NS_ENSURE_SUCCESS(rv, rv);
1737 : // The floats are not in flow
1738 0 : rv = WrapEachDisplayItem(aBuilder, aLists.Floats(), this);
1739 0 : NS_ENSURE_SUCCESS(rv, rv);
1740 : // Our child content is in flow
1741 0 : rv = WrapDisplayList(aBuilder, aFrame, aLists.Content(), this);
1742 0 : NS_ENSURE_SUCCESS(rv, rv);
1743 : // The positioned descendants may not be in-flow
1744 0 : rv = WrapEachDisplayItem(aBuilder, aLists.PositionedDescendants(), this);
1745 0 : NS_ENSURE_SUCCESS(rv, rv);
1746 : // The outlines may not be in-flow
1747 0 : return WrapEachDisplayItem(aBuilder, aLists.Outlines(), this);
1748 : }
1749 :
1750 0 : nsDisplayOpacity::nsDisplayOpacity(nsDisplayListBuilder* aBuilder,
1751 : nsIFrame* aFrame, nsDisplayList* aList)
1752 0 : : nsDisplayWrapList(aBuilder, aFrame, aList) {
1753 0 : MOZ_COUNT_CTOR(nsDisplayOpacity);
1754 0 : }
1755 :
1756 : #ifdef NS_BUILD_REFCNT_LOGGING
1757 0 : nsDisplayOpacity::~nsDisplayOpacity() {
1758 0 : MOZ_COUNT_DTOR(nsDisplayOpacity);
1759 0 : }
1760 : #endif
1761 :
1762 0 : nsRegion nsDisplayOpacity::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
1763 : bool* aForceTransparentSurface) {
1764 0 : if (aForceTransparentSurface) {
1765 0 : *aForceTransparentSurface = false;
1766 : }
1767 : // We are never opaque, if our opacity was < 1 then we wouldn't have
1768 : // been created.
1769 0 : return nsRegion();
1770 : }
1771 :
1772 : // nsDisplayOpacity uses layers for rendering
1773 : already_AddRefed<Layer>
1774 0 : nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder,
1775 : LayerManager* aManager,
1776 : const ContainerParameters& aContainerParameters) {
1777 : nsRefPtr<Layer> layer = aBuilder->LayerBuilder()->
1778 : BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
1779 0 : aContainerParameters, nsnull);
1780 0 : if (!layer)
1781 0 : return nsnull;
1782 :
1783 0 : layer->SetOpacity(mFrame->GetStyleDisplay()->mOpacity);
1784 0 : return layer.forget();
1785 : }
1786 :
1787 : /**
1788 : * This doesn't take into account layer scaling --- the layer may be
1789 : * rendered at a higher (or lower) resolution, affecting the retained layer
1790 : * size --- but this should be good enough.
1791 : */
1792 : static bool
1793 0 : IsItemTooSmallForActiveLayer(nsDisplayItem* aItem)
1794 : {
1795 0 : nsIntRect visibleDevPixels = aItem->GetVisibleRect().ToOutsidePixels(
1796 0 : aItem->GetUnderlyingFrame()->PresContext()->AppUnitsPerDevPixel());
1797 : static const int MIN_ACTIVE_LAYER_SIZE_DEV_PIXELS = 16;
1798 : return visibleDevPixels.Size() <
1799 0 : nsIntSize(MIN_ACTIVE_LAYER_SIZE_DEV_PIXELS, MIN_ACTIVE_LAYER_SIZE_DEV_PIXELS);
1800 : }
1801 :
1802 : nsDisplayItem::LayerState
1803 0 : nsDisplayOpacity::GetLayerState(nsDisplayListBuilder* aBuilder,
1804 : LayerManager* aManager) {
1805 0 : if (mFrame->AreLayersMarkedActive(nsChangeHint_UpdateOpacityLayer) &&
1806 0 : !IsItemTooSmallForActiveLayer(this))
1807 0 : return LAYER_ACTIVE;
1808 : nsIFrame* activeScrolledRoot =
1809 0 : nsLayoutUtils::GetActiveScrolledRootFor(mFrame, nsnull);
1810 0 : return !ChildrenCanBeInactive(aBuilder, aManager, mList, activeScrolledRoot)
1811 0 : ? LAYER_ACTIVE : LAYER_INACTIVE;
1812 : }
1813 :
1814 : bool
1815 0 : nsDisplayOpacity::ComputeVisibility(nsDisplayListBuilder* aBuilder,
1816 : nsRegion* aVisibleRegion,
1817 : const nsRect& aAllowVisibleRegionExpansion) {
1818 : // Our children are translucent so we should not allow them to subtract
1819 : // area from aVisibleRegion. We do need to find out what is visible under
1820 : // our children in the temporary compositing buffer, because if our children
1821 : // paint our entire bounds opaquely then we don't need an alpha channel in
1822 : // the temporary compositing buffer.
1823 0 : nsRect bounds = GetBounds(aBuilder);
1824 0 : nsRegion visibleUnderChildren;
1825 0 : visibleUnderChildren.And(*aVisibleRegion, bounds);
1826 0 : nsRect allowExpansion;
1827 0 : allowExpansion.IntersectRect(bounds, aAllowVisibleRegionExpansion);
1828 : return
1829 : nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleUnderChildren,
1830 0 : allowExpansion);
1831 : }
1832 :
1833 0 : bool nsDisplayOpacity::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) {
1834 0 : if (aItem->GetType() != TYPE_OPACITY)
1835 0 : return false;
1836 : // items for the same content element should be merged into a single
1837 : // compositing group
1838 : // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity
1839 0 : if (aItem->GetUnderlyingFrame()->GetContent() != mFrame->GetContent())
1840 0 : return false;
1841 0 : mList.AppendToBottom(&static_cast<nsDisplayOpacity*>(aItem)->mList);
1842 0 : return true;
1843 : }
1844 :
1845 0 : nsDisplayOwnLayer::nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder,
1846 : nsIFrame* aFrame, nsDisplayList* aList)
1847 0 : : nsDisplayWrapList(aBuilder, aFrame, aList) {
1848 0 : MOZ_COUNT_CTOR(nsDisplayOwnLayer);
1849 0 : }
1850 :
1851 : #ifdef NS_BUILD_REFCNT_LOGGING
1852 0 : nsDisplayOwnLayer::~nsDisplayOwnLayer() {
1853 0 : MOZ_COUNT_DTOR(nsDisplayOwnLayer);
1854 0 : }
1855 : #endif
1856 :
1857 : // nsDisplayOpacity uses layers for rendering
1858 : already_AddRefed<Layer>
1859 0 : nsDisplayOwnLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
1860 : LayerManager* aManager,
1861 : const ContainerParameters& aContainerParameters) {
1862 : nsRefPtr<Layer> layer = aBuilder->LayerBuilder()->
1863 : BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
1864 0 : aContainerParameters, nsnull);
1865 0 : return layer.forget();
1866 : }
1867 :
1868 0 : nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder,
1869 : nsDisplayList* aList,
1870 : nsIFrame* aForFrame,
1871 : nsIFrame* aScrolledFrame,
1872 : nsIFrame* aScrollFrame)
1873 : : nsDisplayWrapList(aBuilder, aForFrame, aList)
1874 : , mScrollFrame(aScrollFrame)
1875 0 : , mScrolledFrame(aScrolledFrame)
1876 : {
1877 : #ifdef NS_BUILD_REFCNT_LOGGING
1878 0 : MOZ_COUNT_CTOR(nsDisplayScrollLayer);
1879 : #endif
1880 :
1881 0 : NS_ASSERTION(mScrolledFrame && mScrolledFrame->GetContent(),
1882 : "Need a child frame with content");
1883 0 : }
1884 :
1885 0 : nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder,
1886 : nsDisplayItem* aItem,
1887 : nsIFrame* aForFrame,
1888 : nsIFrame* aScrolledFrame,
1889 : nsIFrame* aScrollFrame)
1890 : : nsDisplayWrapList(aBuilder, aForFrame, aItem)
1891 : , mScrollFrame(aScrollFrame)
1892 0 : , mScrolledFrame(aScrolledFrame)
1893 : {
1894 : #ifdef NS_BUILD_REFCNT_LOGGING
1895 0 : MOZ_COUNT_CTOR(nsDisplayScrollLayer);
1896 : #endif
1897 :
1898 0 : NS_ASSERTION(mScrolledFrame && mScrolledFrame->GetContent(),
1899 : "Need a child frame with content");
1900 0 : }
1901 :
1902 0 : nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder,
1903 : nsIFrame* aForFrame,
1904 : nsIFrame* aScrolledFrame,
1905 : nsIFrame* aScrollFrame)
1906 : : nsDisplayWrapList(aBuilder, aForFrame)
1907 : , mScrollFrame(aScrollFrame)
1908 0 : , mScrolledFrame(aScrolledFrame)
1909 : {
1910 : #ifdef NS_BUILD_REFCNT_LOGGING
1911 0 : MOZ_COUNT_CTOR(nsDisplayScrollLayer);
1912 : #endif
1913 :
1914 0 : NS_ASSERTION(mScrolledFrame && mScrolledFrame->GetContent(),
1915 : "Need a child frame with content");
1916 0 : }
1917 :
1918 : #ifdef NS_BUILD_REFCNT_LOGGING
1919 0 : nsDisplayScrollLayer::~nsDisplayScrollLayer()
1920 : {
1921 0 : MOZ_COUNT_DTOR(nsDisplayScrollLayer);
1922 0 : }
1923 : #endif
1924 :
1925 : already_AddRefed<Layer>
1926 0 : nsDisplayScrollLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
1927 : LayerManager* aManager,
1928 : const ContainerParameters& aContainerParameters) {
1929 : nsRefPtr<ContainerLayer> layer = aBuilder->LayerBuilder()->
1930 : BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
1931 0 : aContainerParameters, nsnull);
1932 :
1933 : // Get the already set unique ID for scrolling this content remotely.
1934 : // Or, if not set, generate a new ID.
1935 0 : nsIContent* content = mScrolledFrame->GetContent();
1936 0 : ViewID scrollId = nsLayoutUtils::FindIDFor(content);
1937 :
1938 0 : nsRect viewport = mScrollFrame->GetRect() -
1939 0 : mScrollFrame->GetPosition() +
1940 0 : aBuilder->ToReferenceFrame(mScrollFrame);
1941 :
1942 0 : bool usingDisplayport = false;
1943 0 : nsRect displayport;
1944 0 : if (content) {
1945 0 : usingDisplayport = nsLayoutUtils::GetDisplayPort(content, &displayport);
1946 : }
1947 : RecordFrameMetrics(mScrolledFrame, mScrollFrame, layer, mVisibleRect, viewport,
1948 : (usingDisplayport ? &displayport : nsnull), scrollId,
1949 0 : aContainerParameters);
1950 :
1951 0 : return layer.forget();
1952 : }
1953 :
1954 : bool
1955 0 : nsDisplayScrollLayer::ComputeVisibility(nsDisplayListBuilder* aBuilder,
1956 : nsRegion* aVisibleRegion,
1957 : const nsRect& aAllowVisibleRegionExpansion)
1958 : {
1959 0 : nsRect displayport;
1960 0 : if (nsLayoutUtils::GetDisplayPort(mScrolledFrame->GetContent(), &displayport)) {
1961 : // The visible region for the children may be much bigger than the hole we
1962 : // are viewing the children from, so that the compositor process has enough
1963 : // content to asynchronously pan while content is being refreshed.
1964 :
1965 0 : nsRegion childVisibleRegion = displayport + aBuilder->ToReferenceFrame(mScrollFrame);
1966 :
1967 0 : nsRect boundedRect;
1968 0 : boundedRect.IntersectRect(childVisibleRegion.GetBounds(), mList.GetBounds(aBuilder));
1969 0 : nsRect allowExpansion;
1970 0 : allowExpansion.IntersectRect(allowExpansion, boundedRect);
1971 : bool visible = mList.ComputeVisibilityForSublist(
1972 0 : aBuilder, &childVisibleRegion, boundedRect, allowExpansion);
1973 0 : mVisibleRect = boundedRect;
1974 :
1975 0 : return visible;
1976 :
1977 : } else {
1978 : return nsDisplayWrapList::ComputeVisibility(aBuilder, aVisibleRegion,
1979 0 : aAllowVisibleRegionExpansion);
1980 : }
1981 : }
1982 :
1983 : LayerState
1984 0 : nsDisplayScrollLayer::GetLayerState(nsDisplayListBuilder* aBuilder,
1985 : LayerManager* aManager)
1986 : {
1987 : // Force this as a layer so we can scroll asynchronously.
1988 : // This causes incorrect rendering for rounded clips!
1989 0 : return LAYER_ACTIVE_FORCE;
1990 : }
1991 :
1992 : bool
1993 0 : nsDisplayScrollLayer::TryMerge(nsDisplayListBuilder* aBuilder,
1994 : nsDisplayItem* aItem)
1995 : {
1996 0 : if (aItem->GetType() != TYPE_SCROLL_LAYER) {
1997 0 : return false;
1998 : }
1999 :
2000 0 : nsDisplayScrollLayer* other = static_cast<nsDisplayScrollLayer*>(aItem);
2001 0 : if (other->mScrolledFrame != this->mScrolledFrame) {
2002 0 : return false;
2003 : }
2004 :
2005 0 : FrameProperties props = mScrolledFrame->Properties();
2006 : props.Set(nsIFrame::ScrollLayerCount(),
2007 0 : reinterpret_cast<void*>(GetScrollLayerCount() - 1));
2008 :
2009 0 : mList.AppendToBottom(&other->mList);
2010 : // XXX - This ensures that the frame associated with a scroll layer after
2011 : // merging is the first, rather than the last. This tends to change less,
2012 : // ensuring we're more likely to retain the associated gfx layer.
2013 : // See Bug 729534 and Bug 731641.
2014 0 : mFrame = other->mFrame;
2015 0 : return true;
2016 : }
2017 :
2018 : bool
2019 0 : nsDisplayScrollLayer::ShouldFlattenAway(nsDisplayListBuilder* aBuilder)
2020 : {
2021 0 : return GetScrollLayerCount() > 1;
2022 : }
2023 :
2024 : PRWord
2025 0 : nsDisplayScrollLayer::GetScrollLayerCount()
2026 : {
2027 0 : FrameProperties props = mScrolledFrame->Properties();
2028 : #ifdef DEBUG
2029 0 : bool hasCount = false;
2030 : PRWord result = reinterpret_cast<PRWord>(
2031 0 : props.Get(nsIFrame::ScrollLayerCount(), &hasCount));
2032 : // If this aborts, then the property was either not added before scroll
2033 : // layers were created or the property was deleted to early. If the latter,
2034 : // make sure that nsDisplayScrollInfoLayer is on the bottom of the list so
2035 : // that it is processed last.
2036 0 : NS_ABORT_IF_FALSE(hasCount, "nsDisplayScrollLayer should always be defined");
2037 0 : return result;
2038 : #else
2039 : return reinterpret_cast<PRWord>(props.Get(nsIFrame::ScrollLayerCount()));
2040 : #endif
2041 : }
2042 :
2043 : PRWord
2044 0 : nsDisplayScrollLayer::RemoveScrollLayerCount()
2045 : {
2046 0 : PRWord result = GetScrollLayerCount();
2047 0 : FrameProperties props = mScrolledFrame->Properties();
2048 0 : props.Remove(nsIFrame::ScrollLayerCount());
2049 0 : return result;
2050 : }
2051 :
2052 :
2053 0 : nsDisplayScrollInfoLayer::nsDisplayScrollInfoLayer(
2054 : nsDisplayListBuilder* aBuilder,
2055 : nsIFrame* aScrolledFrame,
2056 : nsIFrame* aScrollFrame)
2057 0 : : nsDisplayScrollLayer(aBuilder, aScrolledFrame, aScrolledFrame, aScrollFrame)
2058 : {
2059 : #ifdef NS_BUILD_REFCNT_LOGGING
2060 0 : MOZ_COUNT_CTOR(nsDisplayScrollInfoLayer);
2061 : #endif
2062 0 : }
2063 :
2064 : #ifdef NS_BUILD_REFCNT_LOGGING
2065 0 : nsDisplayScrollInfoLayer::~nsDisplayScrollInfoLayer()
2066 : {
2067 0 : MOZ_COUNT_DTOR(nsDisplayScrollInfoLayer);
2068 0 : }
2069 : #endif
2070 :
2071 : LayerState
2072 0 : nsDisplayScrollInfoLayer::GetLayerState(nsDisplayListBuilder* aBuilder,
2073 : LayerManager* aManager)
2074 : {
2075 0 : return LAYER_ACTIVE_EMPTY;
2076 : }
2077 :
2078 : bool
2079 0 : nsDisplayScrollInfoLayer::TryMerge(nsDisplayListBuilder* aBuilder,
2080 : nsDisplayItem* aItem)
2081 : {
2082 0 : return false;
2083 : }
2084 :
2085 : bool
2086 0 : nsDisplayScrollInfoLayer::ShouldFlattenAway(nsDisplayListBuilder* aBuilder)
2087 : {
2088 : // Layer metadata for a particular scroll frame needs to be unique. Only
2089 : // one nsDisplayScrollLayer (with rendered content) or one
2090 : // nsDisplayScrollInfoLayer (with only the metadata) should survive the
2091 : // visibility computation.
2092 0 : return RemoveScrollLayerCount() == 1;
2093 : }
2094 :
2095 0 : nsDisplayClip::nsDisplayClip(nsDisplayListBuilder* aBuilder,
2096 : nsIFrame* aFrame, nsDisplayItem* aItem,
2097 : const nsRect& aRect)
2098 0 : : nsDisplayWrapList(aBuilder, aFrame, aItem) {
2099 0 : MOZ_COUNT_CTOR(nsDisplayClip);
2100 0 : mClip = SnapBounds(aBuilder->IsSnappingEnabled() && !aBuilder->IsInTransform(),
2101 0 : aBuilder->CurrentPresContext(), aRect);
2102 0 : }
2103 :
2104 0 : nsDisplayClip::nsDisplayClip(nsDisplayListBuilder* aBuilder,
2105 : nsIFrame* aFrame, nsDisplayList* aList,
2106 : const nsRect& aRect)
2107 0 : : nsDisplayWrapList(aBuilder, aFrame, aList) {
2108 0 : MOZ_COUNT_CTOR(nsDisplayClip);
2109 0 : mClip = SnapBounds(aBuilder->IsSnappingEnabled() && !aBuilder->IsInTransform(),
2110 0 : aBuilder->CurrentPresContext(), aRect);
2111 0 : }
2112 :
2113 0 : nsRect nsDisplayClip::GetBounds(nsDisplayListBuilder* aBuilder) {
2114 0 : nsRect r = nsDisplayWrapList::GetBounds(aBuilder);
2115 0 : r.IntersectRect(mClip, r);
2116 : return r;
2117 : }
2118 :
2119 : #ifdef NS_BUILD_REFCNT_LOGGING
2120 0 : nsDisplayClip::~nsDisplayClip() {
2121 0 : MOZ_COUNT_DTOR(nsDisplayClip);
2122 0 : }
2123 : #endif
2124 :
2125 0 : void nsDisplayClip::Paint(nsDisplayListBuilder* aBuilder,
2126 : nsRenderingContext* aCtx) {
2127 0 : NS_ERROR("nsDisplayClip should have been flattened away for painting");
2128 0 : }
2129 :
2130 0 : bool nsDisplayClip::ComputeVisibility(nsDisplayListBuilder* aBuilder,
2131 : nsRegion* aVisibleRegion,
2132 : const nsRect& aAllowVisibleRegionExpansion) {
2133 0 : nsRegion clipped;
2134 0 : clipped.And(*aVisibleRegion, mClip);
2135 :
2136 0 : nsRegion finalClipped(clipped);
2137 0 : nsRect allowExpansion;
2138 0 : allowExpansion.IntersectRect(mClip, aAllowVisibleRegionExpansion);
2139 : bool anyVisible =
2140 : nsDisplayWrapList::ComputeVisibility(aBuilder, &finalClipped,
2141 0 : allowExpansion);
2142 :
2143 0 : nsRegion removed;
2144 0 : removed.Sub(clipped, finalClipped);
2145 0 : aBuilder->SubtractFromVisibleRegion(aVisibleRegion, removed);
2146 :
2147 0 : return anyVisible;
2148 : }
2149 :
2150 0 : bool nsDisplayClip::TryMerge(nsDisplayListBuilder* aBuilder,
2151 : nsDisplayItem* aItem) {
2152 0 : if (aItem->GetType() != TYPE_CLIP)
2153 0 : return false;
2154 0 : nsDisplayClip* other = static_cast<nsDisplayClip*>(aItem);
2155 0 : if (!other->mClip.IsEqualInterior(mClip))
2156 0 : return false;
2157 0 : mList.AppendToBottom(&other->mList);
2158 0 : return true;
2159 : }
2160 :
2161 0 : nsDisplayWrapList* nsDisplayClip::WrapWithClone(nsDisplayListBuilder* aBuilder,
2162 : nsDisplayItem* aItem) {
2163 : return new (aBuilder)
2164 0 : nsDisplayClip(aBuilder, aItem->GetUnderlyingFrame(), aItem, mClip);
2165 : }
2166 :
2167 0 : nsDisplayClipRoundedRect::nsDisplayClipRoundedRect(
2168 : nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
2169 : nsDisplayItem* aItem,
2170 : const nsRect& aRect, nscoord aRadii[8])
2171 0 : : nsDisplayClip(aBuilder, aFrame, aItem, aRect)
2172 : {
2173 0 : MOZ_COUNT_CTOR(nsDisplayClipRoundedRect);
2174 0 : memcpy(mRadii, aRadii, sizeof(mRadii));
2175 0 : }
2176 :
2177 0 : nsDisplayClipRoundedRect::nsDisplayClipRoundedRect(
2178 : nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
2179 : nsDisplayList* aList,
2180 : const nsRect& aRect, nscoord aRadii[8])
2181 0 : : nsDisplayClip(aBuilder, aFrame, aList, aRect)
2182 : {
2183 0 : MOZ_COUNT_CTOR(nsDisplayClipRoundedRect);
2184 0 : memcpy(mRadii, aRadii, sizeof(mRadii));
2185 0 : }
2186 :
2187 : #ifdef NS_BUILD_REFCNT_LOGGING
2188 0 : nsDisplayClipRoundedRect::~nsDisplayClipRoundedRect()
2189 : {
2190 0 : MOZ_COUNT_DTOR(nsDisplayClipRoundedRect);
2191 0 : }
2192 : #endif
2193 :
2194 : nsRegion
2195 0 : nsDisplayClipRoundedRect::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
2196 : bool* aForceTransparentSurface)
2197 : {
2198 0 : if (aForceTransparentSurface) {
2199 0 : *aForceTransparentSurface = false;
2200 : }
2201 0 : return nsRegion();
2202 : }
2203 :
2204 : void
2205 0 : nsDisplayClipRoundedRect::HitTest(nsDisplayListBuilder* aBuilder,
2206 : const nsRect& aRect, HitTestState* aState,
2207 : nsTArray<nsIFrame*> *aOutFrames)
2208 : {
2209 0 : if (!RoundedRectIntersectsRect(mClip, mRadii, aRect)) {
2210 : // aRect doesn't intersect our border-radius curve.
2211 :
2212 : // FIXME: This isn't quite sufficient for aRect having nontrivial
2213 : // size (which is the unusual case here), since it's possible that
2214 : // the part of aRect that intersects the the rounded rect isn't the
2215 : // part that intersects the items in mList.
2216 0 : return;
2217 : }
2218 :
2219 0 : mList.HitTest(aBuilder, aRect, aState, aOutFrames);
2220 : }
2221 :
2222 : nsDisplayWrapList*
2223 0 : nsDisplayClipRoundedRect::WrapWithClone(nsDisplayListBuilder* aBuilder,
2224 : nsDisplayItem* aItem) {
2225 : return new (aBuilder)
2226 : nsDisplayClipRoundedRect(aBuilder, aItem->GetUnderlyingFrame(), aItem,
2227 0 : mClip, mRadii);
2228 : }
2229 :
2230 0 : bool nsDisplayClipRoundedRect::ComputeVisibility(
2231 : nsDisplayListBuilder* aBuilder,
2232 : nsRegion* aVisibleRegion,
2233 : const nsRect& aAllowVisibleRegionExpansion)
2234 : {
2235 0 : nsRegion clipped;
2236 0 : clipped.And(*aVisibleRegion, mClip);
2237 :
2238 0 : return nsDisplayWrapList::ComputeVisibility(aBuilder, &clipped, nsRect());
2239 : // FIXME: Remove a *conservative* opaque region from aVisibleRegion
2240 : // (like in nsDisplayClip::ComputeVisibility).
2241 : }
2242 :
2243 0 : bool nsDisplayClipRoundedRect::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem)
2244 : {
2245 0 : if (aItem->GetType() != TYPE_CLIP_ROUNDED_RECT)
2246 0 : return false;
2247 : nsDisplayClipRoundedRect* other =
2248 0 : static_cast<nsDisplayClipRoundedRect*>(aItem);
2249 0 : if (!mClip.IsEqualInterior(other->mClip) ||
2250 0 : memcmp(mRadii, other->mRadii, sizeof(mRadii)) != 0)
2251 0 : return false;
2252 0 : mList.AppendToBottom(&other->mList);
2253 0 : return true;
2254 : }
2255 :
2256 0 : nsDisplayZoom::nsDisplayZoom(nsDisplayListBuilder* aBuilder,
2257 : nsIFrame* aFrame, nsDisplayList* aList,
2258 : PRInt32 aAPD, PRInt32 aParentAPD)
2259 : : nsDisplayOwnLayer(aBuilder, aFrame, aList), mAPD(aAPD),
2260 0 : mParentAPD(aParentAPD) {
2261 0 : MOZ_COUNT_CTOR(nsDisplayZoom);
2262 0 : }
2263 :
2264 : #ifdef NS_BUILD_REFCNT_LOGGING
2265 0 : nsDisplayZoom::~nsDisplayZoom() {
2266 0 : MOZ_COUNT_DTOR(nsDisplayZoom);
2267 0 : }
2268 : #endif
2269 :
2270 0 : nsRect nsDisplayZoom::GetBounds(nsDisplayListBuilder* aBuilder)
2271 : {
2272 0 : nsRect bounds = nsDisplayWrapList::GetBounds(aBuilder);
2273 0 : return bounds.ConvertAppUnitsRoundOut(mAPD, mParentAPD);
2274 : }
2275 :
2276 0 : void nsDisplayZoom::HitTest(nsDisplayListBuilder *aBuilder,
2277 : const nsRect& aRect,
2278 : HitTestState *aState,
2279 : nsTArray<nsIFrame*> *aOutFrames)
2280 : {
2281 0 : nsRect rect;
2282 : // A 1x1 rect indicates we are just hit testing a point, so pass down a 1x1
2283 : // rect as well instead of possibly rounding the width or height to zero.
2284 0 : if (aRect.width == 1 && aRect.height == 1) {
2285 0 : rect.MoveTo(aRect.TopLeft().ConvertAppUnits(mParentAPD, mAPD));
2286 0 : rect.width = rect.height = 1;
2287 : } else {
2288 0 : rect = aRect.ConvertAppUnitsRoundOut(mParentAPD, mAPD);
2289 : }
2290 0 : mList.HitTest(aBuilder, rect, aState, aOutFrames);
2291 0 : }
2292 :
2293 0 : void nsDisplayZoom::Paint(nsDisplayListBuilder* aBuilder,
2294 : nsRenderingContext* aCtx)
2295 : {
2296 0 : mList.PaintForFrame(aBuilder, aCtx, mFrame, nsDisplayList::PAINT_DEFAULT);
2297 0 : }
2298 :
2299 0 : bool nsDisplayZoom::ComputeVisibility(nsDisplayListBuilder *aBuilder,
2300 : nsRegion *aVisibleRegion,
2301 : const nsRect& aAllowVisibleRegionExpansion)
2302 : {
2303 : // Convert the passed in visible region to our appunits.
2304 : nsRegion visibleRegion =
2305 0 : aVisibleRegion->ConvertAppUnitsRoundOut(mParentAPD, mAPD);
2306 0 : nsRegion originalVisibleRegion = visibleRegion;
2307 :
2308 : nsRect transformedVisibleRect =
2309 0 : mVisibleRect.ConvertAppUnitsRoundOut(mParentAPD, mAPD);
2310 : nsRect allowExpansion =
2311 0 : aAllowVisibleRegionExpansion.ConvertAppUnitsRoundIn(mParentAPD, mAPD);
2312 : bool retval =
2313 : mList.ComputeVisibilityForSublist(aBuilder, &visibleRegion,
2314 : transformedVisibleRect,
2315 0 : allowExpansion);
2316 :
2317 0 : nsRegion removed;
2318 : // removed = originalVisibleRegion - visibleRegion
2319 0 : removed.Sub(originalVisibleRegion, visibleRegion);
2320 : // Convert removed region to parent appunits.
2321 0 : removed = removed.ConvertAppUnitsRoundIn(mAPD, mParentAPD);
2322 : // aVisibleRegion = aVisibleRegion - removed (modulo any simplifications
2323 : // SubtractFromVisibleRegion does)
2324 0 : aBuilder->SubtractFromVisibleRegion(aVisibleRegion, removed);
2325 :
2326 0 : return retval;
2327 : }
2328 :
2329 : ///////////////////////////////////////////////////
2330 : // nsDisplayTransform Implementation
2331 : //
2332 :
2333 : // Write #define UNIFIED_CONTINUATIONS here to have the transform property try
2334 : // to transform content with continuations as one unified block instead of
2335 : // several smaller ones. This is currently disabled because it doesn't work
2336 : // correctly, since when the frames are initially being reflowed, their
2337 : // continuations all compute their bounding rects independently of each other
2338 : // and consequently get the wrong value. Write #define DEBUG_HIT here to have
2339 : // the nsDisplayTransform class dump out a bunch of information about hit
2340 : // detection.
2341 : #undef UNIFIED_CONTINUATIONS
2342 : #undef DEBUG_HIT
2343 :
2344 : /* Returns the bounds of a frame as defined for transforms. If
2345 : * UNIFIED_CONTINUATIONS is not defined, this is simply the frame's bounding
2346 : * rectangle, translated to the origin. Otherwise, returns the smallest
2347 : * rectangle containing a frame and all of its continuations. For example, if
2348 : * there is a <span> element with several continuations split over several
2349 : * lines, this function will return the rectangle containing all of those
2350 : * continuations. This rectangle is relative to the origin of the frame's local
2351 : * coordinate space.
2352 : */
2353 : #ifndef UNIFIED_CONTINUATIONS
2354 :
2355 : nsRect
2356 0 : nsDisplayTransform::GetFrameBoundsForTransform(const nsIFrame* aFrame)
2357 : {
2358 0 : NS_PRECONDITION(aFrame, "Can't get the bounds of a nonexistent frame!");
2359 0 : return nsRect(nsPoint(0, 0), aFrame->GetSize());
2360 : }
2361 :
2362 : #else
2363 :
2364 : nsRect
2365 : nsDisplayTransform::GetFrameBoundsForTransform(const nsIFrame* aFrame)
2366 : {
2367 : NS_PRECONDITION(aFrame, "Can't get the bounds of a nonexistent frame!");
2368 :
2369 : nsRect result;
2370 :
2371 : /* Iterate through the continuation list, unioning together all the
2372 : * bounding rects.
2373 : */
2374 : for (const nsIFrame *currFrame = aFrame->GetFirstContinuation();
2375 : currFrame != nsnull;
2376 : currFrame = currFrame->GetNextContinuation())
2377 : {
2378 : /* Get the frame rect in local coordinates, then translate back to the
2379 : * original coordinates.
2380 : */
2381 : result.UnionRect(result, nsRect(currFrame->GetOffsetTo(aFrame),
2382 : currFrame->GetSize()));
2383 : }
2384 :
2385 : return result;
2386 : }
2387 :
2388 : #endif
2389 :
2390 : /* Returns the delta specified by the -moz-transform-origin property.
2391 : * This is a positive delta, meaning that it indicates the direction to move
2392 : * to get from (0, 0) of the frame to the transform origin.
2393 : */
2394 : static
2395 0 : gfxPoint3D GetDeltaToMozTransformOrigin(const nsIFrame* aFrame,
2396 : float aAppUnitsPerPixel,
2397 : const nsRect* aBoundsOverride)
2398 : {
2399 0 : NS_PRECONDITION(aFrame, "Can't get delta for a null frame!");
2400 0 : NS_PRECONDITION(aFrame->GetStyleDisplay()->HasTransform(),
2401 : "Can't get a delta for an untransformed frame!");
2402 :
2403 : /* For both of the coordinates, if the value of -moz-transform is a
2404 : * percentage, it's relative to the size of the frame. Otherwise, if it's
2405 : * a distance, it's already computed for us!
2406 : */
2407 0 : const nsStyleDisplay* display = aFrame->GetStyleDisplay();
2408 : nsRect boundingRect = (aBoundsOverride ? *aBoundsOverride :
2409 0 : nsDisplayTransform::GetFrameBoundsForTransform(aFrame));
2410 :
2411 : /* Allows us to access named variables by index. */
2412 0 : gfxPoint3D result;
2413 0 : gfxFloat* coords[3] = {&result.x, &result.y, &result.z};
2414 : const nscoord* dimensions[2] =
2415 0 : {&boundingRect.width, &boundingRect.height};
2416 :
2417 0 : for (PRUint8 index = 0; index < 2; ++index) {
2418 : /* If the -moz-transform-origin specifies a percentage, take the percentage
2419 : * of the size of the box.
2420 : */
2421 0 : const nsStyleCoord &coord = display->mTransformOrigin[index];
2422 0 : if (coord.GetUnit() == eStyleUnit_Calc) {
2423 0 : const nsStyleCoord::Calc *calc = coord.GetCalcValue();
2424 0 : *coords[index] =
2425 0 : NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) *
2426 : calc->mPercent +
2427 0 : NSAppUnitsToFloatPixels(calc->mLength, aAppUnitsPerPixel);
2428 0 : } else if (coord.GetUnit() == eStyleUnit_Percent) {
2429 0 : *coords[index] =
2430 0 : NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) *
2431 0 : coord.GetPercentValue();
2432 : } else {
2433 0 : NS_ABORT_IF_FALSE(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
2434 0 : *coords[index] =
2435 0 : NSAppUnitsToFloatPixels(coord.GetCoordValue(), aAppUnitsPerPixel);
2436 : }
2437 : }
2438 :
2439 0 : *coords[2] = NSAppUnitsToFloatPixels(display->mTransformOrigin[2].GetCoordValue(),
2440 0 : aAppUnitsPerPixel);
2441 : /* Adjust based on the origin of the rectangle. */
2442 0 : result.x += NSAppUnitsToFloatPixels(boundingRect.x, aAppUnitsPerPixel);
2443 0 : result.y += NSAppUnitsToFloatPixels(boundingRect.y, aAppUnitsPerPixel);
2444 :
2445 : return result;
2446 : }
2447 :
2448 : /* Returns the delta specified by the -moz-perspective-origin property.
2449 : * This is a positive delta, meaning that it indicates the direction to move
2450 : * to get from (0, 0) of the frame to the perspective origin.
2451 : */
2452 : static
2453 0 : gfxPoint3D GetDeltaToMozPerspectiveOrigin(const nsIFrame* aFrame,
2454 : float aAppUnitsPerPixel)
2455 : {
2456 0 : NS_PRECONDITION(aFrame, "Can't get delta for a null frame!");
2457 0 : NS_PRECONDITION(aFrame->GetStyleDisplay()->HasTransform(),
2458 : "Can't get a delta for an untransformed frame!");
2459 0 : NS_PRECONDITION(aFrame->GetParentStyleContextFrame(),
2460 : "Can't get delta without a style parent!");
2461 :
2462 : /* For both of the coordinates, if the value of -moz-perspective-origin is a
2463 : * percentage, it's relative to the size of the frame. Otherwise, if it's
2464 : * a distance, it's already computed for us!
2465 : */
2466 :
2467 : //TODO: Should this be using our bounds or the parent's bounds?
2468 : // How do we handle aBoundsOverride in the latter case?
2469 0 : nsIFrame* parent = aFrame->GetParentStyleContextFrame();
2470 0 : const nsStyleDisplay* display = aFrame->GetParent()->GetStyleDisplay();
2471 0 : nsRect boundingRect = nsDisplayTransform::GetFrameBoundsForTransform(parent);
2472 :
2473 : /* Allows us to access named variables by index. */
2474 0 : gfxPoint3D result;
2475 0 : result.z = 0.0f;
2476 0 : gfxFloat* coords[2] = {&result.x, &result.y};
2477 : const nscoord* dimensions[2] =
2478 0 : {&boundingRect.width, &boundingRect.height};
2479 :
2480 0 : for (PRUint8 index = 0; index < 2; ++index) {
2481 : /* If the -moz-transform-origin specifies a percentage, take the percentage
2482 : * of the size of the box.
2483 : */
2484 0 : const nsStyleCoord &coord = display->mPerspectiveOrigin[index];
2485 0 : if (coord.GetUnit() == eStyleUnit_Calc) {
2486 0 : const nsStyleCoord::Calc *calc = coord.GetCalcValue();
2487 0 : *coords[index] =
2488 0 : NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) *
2489 : calc->mPercent +
2490 0 : NSAppUnitsToFloatPixels(calc->mLength, aAppUnitsPerPixel);
2491 0 : } else if (coord.GetUnit() == eStyleUnit_Percent) {
2492 0 : *coords[index] =
2493 0 : NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) *
2494 0 : coord.GetPercentValue();
2495 : } else {
2496 0 : NS_ABORT_IF_FALSE(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
2497 0 : *coords[index] =
2498 0 : NSAppUnitsToFloatPixels(coord.GetCoordValue(), aAppUnitsPerPixel);
2499 : }
2500 : }
2501 :
2502 0 : nsPoint parentOffset = aFrame->GetOffsetTo(parent);
2503 : gfxPoint3D gfxOffset(
2504 0 : NSAppUnitsToFloatPixels(parentOffset.x, aAppUnitsPerPixel),
2505 0 : NSAppUnitsToFloatPixels(parentOffset.y, aAppUnitsPerPixel),
2506 0 : 0.0f);
2507 :
2508 0 : return result - gfxOffset;
2509 : }
2510 :
2511 : /* Wraps up the -moz-transform matrix in a change-of-basis matrix pair that
2512 : * translates from local coordinate space to transform coordinate space, then
2513 : * hands it back.
2514 : */
2515 : gfx3DMatrix
2516 0 : nsDisplayTransform::GetResultingTransformMatrix(const nsIFrame* aFrame,
2517 : const nsPoint &aOrigin,
2518 : float aAppUnitsPerPixel,
2519 : const nsRect* aBoundsOverride,
2520 : nsIFrame** aOutAncestor)
2521 : {
2522 0 : NS_PRECONDITION(aFrame, "Cannot get transform matrix for a null frame!");
2523 :
2524 0 : if (aOutAncestor) {
2525 0 : *aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
2526 : }
2527 :
2528 : /* Account for the -moz-transform-origin property by translating the
2529 : * coordinate space to the new origin.
2530 : */
2531 : gfxPoint3D toMozOrigin =
2532 0 : GetDeltaToMozTransformOrigin(aFrame, aAppUnitsPerPixel, aBoundsOverride);
2533 : gfxPoint3D newOrigin =
2534 0 : gfxPoint3D(NSAppUnitsToFloatPixels(aOrigin.x, aAppUnitsPerPixel),
2535 0 : NSAppUnitsToFloatPixels(aOrigin.y, aAppUnitsPerPixel),
2536 0 : 0.0f);
2537 :
2538 : /* Get the underlying transform matrix. This requires us to get the
2539 : * bounds of the frame.
2540 : */
2541 0 : const nsStyleDisplay* disp = aFrame->GetStyleDisplay();
2542 : nsRect bounds = (aBoundsOverride ? *aBoundsOverride :
2543 0 : nsDisplayTransform::GetFrameBoundsForTransform(aFrame));
2544 :
2545 : /* Get the matrix, then change its basis to factor in the origin. */
2546 : bool dummy;
2547 0 : gfx3DMatrix result;
2548 : /* Transformed frames always have a transform, or are preserving 3d (and might still have perspective!) */
2549 0 : if (disp->mSpecifiedTransform) {
2550 : result = nsStyleTransformMatrix::ReadTransforms(disp->mSpecifiedTransform,
2551 : aFrame->GetStyleContext(),
2552 : aFrame->PresContext(),
2553 0 : dummy, bounds, aAppUnitsPerPixel);
2554 : } else {
2555 0 : NS_ASSERTION(aFrame->GetStyleDisplay()->mTransformStyle == NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D ||
2556 : aFrame->GetStyleDisplay()->mBackfaceVisibility == NS_STYLE_BACKFACE_VISIBILITY_HIDDEN,
2557 : "If we don't have a transform, then we must have another reason to have an nsDisplayTransform created");
2558 : }
2559 :
2560 0 : const nsStyleDisplay* parentDisp = nsnull;
2561 0 : nsStyleContext* parentStyleContext = aFrame->GetStyleContext()->GetParent();
2562 0 : if (parentStyleContext) {
2563 0 : parentDisp = parentStyleContext->GetStyleDisplay();
2564 : }
2565 0 : if (nsLayoutUtils::Are3DTransformsEnabled() &&
2566 0 : parentDisp && parentDisp->mChildPerspective.GetUnit() == eStyleUnit_Coord &&
2567 0 : parentDisp->mChildPerspective.GetCoordValue() > 0.0) {
2568 0 : gfx3DMatrix perspective;
2569 : perspective._34 =
2570 : -1.0 / NSAppUnitsToFloatPixels(parentDisp->mChildPerspective.GetCoordValue(),
2571 0 : aAppUnitsPerPixel);
2572 : /* At the point when perspective is applied, we have been translated to the transform origin.
2573 : * The translation to the perspective origin is the difference between these values.
2574 : */
2575 0 : gfxPoint3D toPerspectiveOrigin = GetDeltaToMozPerspectiveOrigin(aFrame, aAppUnitsPerPixel);
2576 0 : result = result * nsLayoutUtils::ChangeMatrixBasis(toPerspectiveOrigin - toMozOrigin, perspective);
2577 : }
2578 :
2579 0 : if (aFrame->Preserves3D() && nsLayoutUtils::Are3DTransformsEnabled()) {
2580 : // Include the transform set on our parent
2581 0 : NS_ASSERTION(aFrame->GetParent() &&
2582 : aFrame->GetParent()->IsTransformed() &&
2583 : aFrame->GetParent()->Preserves3DChildren(),
2584 : "Preserve3D mismatch!");
2585 0 : gfx3DMatrix parent = GetResultingTransformMatrix(aFrame->GetParent(), aOrigin - aFrame->GetPosition(),
2586 0 : aAppUnitsPerPixel, nsnull, aOutAncestor);
2587 0 : return nsLayoutUtils::ChangeMatrixBasis(newOrigin + toMozOrigin, result) * parent;
2588 : }
2589 :
2590 : return nsLayoutUtils::ChangeMatrixBasis
2591 0 : (newOrigin + toMozOrigin, result);
2592 : }
2593 :
2594 : bool
2595 0 : nsDisplayTransform::ShouldPrerenderTransformedContent(nsDisplayListBuilder* aBuilder,
2596 : nsIFrame* aFrame)
2597 : {
2598 0 : if (aFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer)) {
2599 0 : nsSize refSize = aBuilder->ReferenceFrame()->GetSize();
2600 : // Only prerender if the transformed frame's size is <= the
2601 : // reference frame size (~viewport), allowing a 1/8th fuzz factor
2602 : // for shadows, borders, etc.
2603 0 : refSize += nsSize(refSize.width / 8, refSize.height / 8);
2604 0 : if (aFrame->GetVisualOverflowRectRelativeToSelf().Size() <= refSize) {
2605 : // Bug 717521 - pre-render max 4096 x 4096 device pixels.
2606 0 : nscoord max = aFrame->PresContext()->DevPixelsToAppUnits(4096);
2607 0 : nsRect visual = aFrame->GetVisualOverflowRect();
2608 0 : if (visual.width <= max && visual.height <= max) {
2609 0 : return true;
2610 : }
2611 : }
2612 : }
2613 0 : return false;
2614 : }
2615 :
2616 : /* If the matrix is singular, or a hidden backface is shown, the frame won't be visible or hit. */
2617 0 : static bool IsFrameVisible(nsIFrame* aFrame, const gfx3DMatrix& aMatrix)
2618 : {
2619 0 : if (aMatrix.IsSingular()) {
2620 0 : return false;
2621 : }
2622 0 : if (aFrame->GetStyleDisplay()->mBackfaceVisibility == NS_STYLE_BACKFACE_VISIBILITY_HIDDEN &&
2623 0 : aMatrix.IsBackfaceVisible()) {
2624 0 : return false;
2625 : }
2626 0 : return true;
2627 : }
2628 :
2629 : const gfx3DMatrix&
2630 0 : nsDisplayTransform::GetTransform(float aAppUnitsPerPixel)
2631 : {
2632 0 : if (mTransform.IsIdentity() || mCachedAppUnitsPerPixel != aAppUnitsPerPixel) {
2633 : mTransform =
2634 0 : GetResultingTransformMatrix(mFrame, ToReferenceFrame(),
2635 : aAppUnitsPerPixel,
2636 0 : nsnull);
2637 0 : mCachedAppUnitsPerPixel = aAppUnitsPerPixel;
2638 : }
2639 0 : return mTransform;
2640 : }
2641 :
2642 0 : already_AddRefed<Layer> nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBuilder,
2643 : LayerManager *aManager,
2644 : const ContainerParameters& aContainerParameters)
2645 : {
2646 : const gfx3DMatrix& newTransformMatrix =
2647 0 : GetTransform(mFrame->PresContext()->AppUnitsPerDevPixel());
2648 :
2649 0 : if (!IsFrameVisible(mFrame, newTransformMatrix)) {
2650 0 : return nsnull;
2651 : }
2652 :
2653 : nsRefPtr<ContainerLayer> container = aBuilder->LayerBuilder()->
2654 0 : BuildContainerLayerFor(aBuilder, aManager, mFrame, this, *mStoredList.GetList(),
2655 0 : aContainerParameters, &newTransformMatrix);
2656 :
2657 : // Add the preserve-3d flag for this layer, BuildContainerLayerFor clears all flags,
2658 : // so we never need to explicitely unset this flag.
2659 0 : if (mFrame->Preserves3D() || mFrame->Preserves3DChildren()) {
2660 0 : container->SetContentFlags(container->GetContentFlags() | Layer::CONTENT_PRESERVE_3D);
2661 : }
2662 0 : return container.forget();
2663 : }
2664 :
2665 : nsDisplayItem::LayerState
2666 0 : nsDisplayTransform::GetLayerState(nsDisplayListBuilder* aBuilder,
2667 : LayerManager* aManager) {
2668 : // Here we check if the *post-transform* bounds of this item are big enough
2669 : // to justify an active layer.
2670 0 : if (mFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer) &&
2671 0 : !IsItemTooSmallForActiveLayer(this))
2672 0 : return LAYER_ACTIVE;
2673 0 : if (!GetTransform(mFrame->PresContext()->AppUnitsPerDevPixel()).Is2D() || mFrame->Preserves3D())
2674 0 : return LAYER_ACTIVE;
2675 : nsIFrame* activeScrolledRoot =
2676 0 : nsLayoutUtils::GetActiveScrolledRootFor(mFrame, nsnull);
2677 : return !mStoredList.ChildrenCanBeInactive(aBuilder,
2678 : aManager,
2679 0 : *mStoredList.GetList(),
2680 0 : activeScrolledRoot)
2681 0 : ? LAYER_ACTIVE : LAYER_INACTIVE;
2682 : }
2683 :
2684 0 : bool nsDisplayTransform::ComputeVisibility(nsDisplayListBuilder *aBuilder,
2685 : nsRegion *aVisibleRegion,
2686 : const nsRect& aAllowVisibleRegionExpansion)
2687 : {
2688 : /* As we do this, we need to be sure to
2689 : * untransform the visible rect, since we want everything that's painting to
2690 : * think that it's painting in its original rectangular coordinate space.
2691 : * If we can't untransform, take the entire overflow rect */
2692 0 : nsRect untransformedVisibleRect;
2693 0 : float factor = nsPresContext::AppUnitsPerCSSPixel();
2694 0 : if (ShouldPrerenderTransformedContent(aBuilder, mFrame) ||
2695 : !UntransformRectMatrix(mVisibleRect,
2696 0 : GetTransform(factor),
2697 : factor,
2698 0 : &untransformedVisibleRect))
2699 : {
2700 0 : untransformedVisibleRect = mFrame->GetVisualOverflowRectRelativeToSelf() +
2701 0 : aBuilder->ToReferenceFrame(mFrame);
2702 : }
2703 0 : nsRegion untransformedVisible = untransformedVisibleRect;
2704 : // Call RecomputeVisiblity instead of ComputeVisibility since
2705 : // nsDisplayItem::ComputeVisibility should only be called from
2706 : // nsDisplayList::ComputeVisibility (which sets mVisibleRect on the item)
2707 0 : mStoredList.RecomputeVisibility(aBuilder, &untransformedVisible);
2708 0 : return true;
2709 : }
2710 :
2711 : #ifdef DEBUG_HIT
2712 : #include <time.h>
2713 : #endif
2714 :
2715 : /* HitTest does some fun stuff with matrix transforms to obtain the answer. */
2716 0 : void nsDisplayTransform::HitTest(nsDisplayListBuilder *aBuilder,
2717 : const nsRect& aRect,
2718 : HitTestState *aState,
2719 : nsTArray<nsIFrame*> *aOutFrames)
2720 : {
2721 : /* Here's how this works:
2722 : * 1. Get the matrix. If it's singular, abort (clearly we didn't hit
2723 : * anything).
2724 : * 2. Invert the matrix.
2725 : * 3. Use it to transform the rect into the correct space.
2726 : * 4. Pass that rect down through to the list's version of HitTest.
2727 : */
2728 0 : float factor = nsPresContext::AppUnitsPerCSSPixel();
2729 0 : gfx3DMatrix matrix = GetTransform(factor);
2730 :
2731 0 : if (!IsFrameVisible(mFrame, matrix)) {
2732 0 : return;
2733 : }
2734 :
2735 : /* We want to go from transformed-space to regular space.
2736 : * Thus we have to invert the matrix, which normally does
2737 : * the reverse operation (e.g. regular->transformed)
2738 : */
2739 :
2740 : /* Now, apply the transform and pass it down the channel. */
2741 0 : nsRect resultingRect;
2742 0 : if (aRect.width == 1 && aRect.height == 1) {
2743 : // Magic width/height indicating we're hit testing a point, not a rect
2744 : gfxPoint point = matrix.Inverse().ProjectPoint(
2745 0 : gfxPoint(NSAppUnitsToFloatPixels(aRect.x, factor),
2746 0 : NSAppUnitsToFloatPixels(aRect.y, factor)));
2747 :
2748 : resultingRect = nsRect(NSFloatPixelsToAppUnits(float(point.x), factor),
2749 : NSFloatPixelsToAppUnits(float(point.y), factor),
2750 0 : 1, 1);
2751 :
2752 : } else {
2753 0 : gfxRect originalRect(NSAppUnitsToFloatPixels(aRect.x, factor),
2754 0 : NSAppUnitsToFloatPixels(aRect.y, factor),
2755 0 : NSAppUnitsToFloatPixels(aRect.width, factor),
2756 0 : NSAppUnitsToFloatPixels(aRect.height, factor));
2757 :
2758 0 : gfxRect rect = matrix.Inverse().ProjectRectBounds(originalRect);;
2759 :
2760 0 : resultingRect = nsRect(NSFloatPixelsToAppUnits(float(rect.X()), factor),
2761 0 : NSFloatPixelsToAppUnits(float(rect.Y()), factor),
2762 0 : NSFloatPixelsToAppUnits(float(rect.Width()), factor),
2763 0 : NSFloatPixelsToAppUnits(float(rect.Height()), factor));
2764 : }
2765 :
2766 :
2767 : #ifdef DEBUG_HIT
2768 : printf("Frame: %p\n", dynamic_cast<void *>(mFrame));
2769 : printf(" Untransformed point: (%f, %f)\n", resultingRect.X(), resultingRect.Y());
2770 : PRUint32 originalFrameCount = aOutFrames.Length();
2771 : #endif
2772 :
2773 0 : mStoredList.HitTest(aBuilder, resultingRect, aState, aOutFrames);
2774 :
2775 : #ifdef DEBUG_HIT
2776 : if (originalFrameCount != aOutFrames.Length())
2777 : printf(" Hit! Time: %f, first frame: %p\n", static_cast<double>(clock()),
2778 : dynamic_cast<void *>(aOutFrames.ElementAt(0)));
2779 : printf("=== end of hit test ===\n");
2780 : #endif
2781 :
2782 : }
2783 :
2784 : float
2785 0 : nsDisplayTransform::GetHitDepthAtPoint(const nsPoint& aPoint)
2786 : {
2787 0 : float factor = nsPresContext::AppUnitsPerCSSPixel();
2788 0 : gfx3DMatrix matrix = GetTransform(factor);
2789 :
2790 0 : NS_ASSERTION(IsFrameVisible(mFrame, matrix), "We can't have hit a frame that isn't visible!");
2791 :
2792 : gfxPoint point =
2793 0 : matrix.Inverse().ProjectPoint(gfxPoint(NSAppUnitsToFloatPixels(aPoint.x, factor),
2794 0 : NSAppUnitsToFloatPixels(aPoint.y, factor)));
2795 :
2796 0 : gfxPoint3D transformed = matrix.Transform3D(gfxPoint3D(point.x, point.y, 0));
2797 0 : return transformed.z;
2798 : }
2799 :
2800 : /* The bounding rectangle for the object is the overflow rectangle translated
2801 : * by the reference point.
2802 : */
2803 0 : nsRect nsDisplayTransform::GetBounds(nsDisplayListBuilder *aBuilder)
2804 : {
2805 : nsRect untransformedBounds =
2806 0 : ShouldPrerenderTransformedContent(aBuilder, mFrame) ?
2807 0 : mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame() :
2808 0 : mStoredList.GetBounds(aBuilder);
2809 0 : float factor = nsPresContext::AppUnitsPerCSSPixel();
2810 : return nsLayoutUtils::MatrixTransformRect(untransformedBounds,
2811 0 : GetTransform(factor),
2812 0 : factor);
2813 : }
2814 :
2815 : /* The transform is opaque iff the transform consists solely of scales and
2816 : * translations and if the underlying content is opaque. Thus if the transform
2817 : * is of the form
2818 : *
2819 : * |a c e|
2820 : * |b d f|
2821 : * |0 0 1|
2822 : *
2823 : * We need b and c to be zero.
2824 : *
2825 : * We also need to check whether the underlying opaque content completely fills
2826 : * our visible rect. We use UntransformRect which expands to the axis-aligned
2827 : * bounding rect, but that's OK since if
2828 : * mStoredList.GetVisibleRect().Contains(untransformedVisible), then it
2829 : * certainly contains the actual (non-axis-aligned) untransformed rect.
2830 : */
2831 0 : nsRegion nsDisplayTransform::GetOpaqueRegion(nsDisplayListBuilder *aBuilder,
2832 : bool* aForceTransparentSurface)
2833 : {
2834 0 : if (aForceTransparentSurface) {
2835 0 : *aForceTransparentSurface = false;
2836 : }
2837 0 : nsRect untransformedVisible;
2838 0 : float factor = nsPresContext::AppUnitsPerCSSPixel();
2839 0 : if (!UntransformRectMatrix(mVisibleRect, GetTransform(factor), factor, &untransformedVisible)) {
2840 0 : return nsRegion();
2841 : }
2842 :
2843 0 : const gfx3DMatrix& matrix = GetTransform(nsPresContext::AppUnitsPerCSSPixel());
2844 :
2845 0 : nsRegion result;
2846 0 : gfxMatrix matrix2d;
2847 0 : if (matrix.Is2D(&matrix2d) &&
2848 0 : matrix2d.PreservesAxisAlignedRectangles() &&
2849 0 : mStoredList.GetOpaqueRegion(aBuilder).Contains(untransformedVisible)) {
2850 0 : result = mVisibleRect;
2851 : }
2852 0 : return result;
2853 : }
2854 :
2855 : /* The transform is uniform if it fills the entire bounding rect and the
2856 : * wrapped list is uniform. See GetOpaqueRegion for discussion of why this
2857 : * works.
2858 : */
2859 0 : bool nsDisplayTransform::IsUniform(nsDisplayListBuilder *aBuilder, nscolor* aColor)
2860 : {
2861 0 : nsRect untransformedVisible;
2862 0 : float factor = nsPresContext::AppUnitsPerCSSPixel();
2863 0 : if (!UntransformRectMatrix(mVisibleRect, GetTransform(factor), factor, &untransformedVisible)) {
2864 0 : return false;
2865 : }
2866 0 : const gfx3DMatrix& matrix = GetTransform(nsPresContext::AppUnitsPerCSSPixel());
2867 :
2868 0 : gfxMatrix matrix2d;
2869 0 : return matrix.Is2D(&matrix2d) &&
2870 0 : matrix2d.PreservesAxisAlignedRectangles() &&
2871 0 : mStoredList.GetVisibleRect().Contains(untransformedVisible) &&
2872 0 : mStoredList.IsUniform(aBuilder, aColor);
2873 : }
2874 :
2875 : /* If UNIFIED_CONTINUATIONS is defined, we can merge two display lists that
2876 : * share the same underlying content. Otherwise, doing so results in graphical
2877 : * glitches.
2878 : */
2879 : #ifndef UNIFIED_CONTINUATIONS
2880 :
2881 : bool
2882 0 : nsDisplayTransform::TryMerge(nsDisplayListBuilder *aBuilder,
2883 : nsDisplayItem *aItem)
2884 : {
2885 0 : return false;
2886 : }
2887 :
2888 : #else
2889 :
2890 : bool
2891 : nsDisplayTransform::TryMerge(nsDisplayListBuilder *aBuilder,
2892 : nsDisplayItem *aItem)
2893 : {
2894 : NS_PRECONDITION(aItem, "Why did you try merging with a null item?");
2895 : NS_PRECONDITION(aBuilder, "Why did you try merging with a null builder?");
2896 :
2897 : /* Make sure that we're dealing with two transforms. */
2898 : if (aItem->GetType() != TYPE_TRANSFORM)
2899 : return false;
2900 :
2901 : /* Check to see that both frames are part of the same content. */
2902 : if (aItem->GetUnderlyingFrame()->GetContent() != mFrame->GetContent())
2903 : return false;
2904 :
2905 : /* Now, move everything over to this frame and signal that
2906 : * we merged things!
2907 : */
2908 : mStoredList.GetList()->
2909 : AppendToBottom(&static_cast<nsDisplayTransform *>(aItem)->mStoredList);
2910 : return true;
2911 : }
2912 :
2913 : #endif
2914 :
2915 : /* TransformRect takes in as parameters a rectangle (in app space) and returns
2916 : * the smallest rectangle (in app space) containing the transformed image of
2917 : * that rectangle. That is, it takes the four corners of the rectangle,
2918 : * transforms them according to the matrix associated with the specified frame,
2919 : * then returns the smallest rectangle containing the four transformed points.
2920 : *
2921 : * @param aUntransformedBounds The rectangle (in app units) to transform.
2922 : * @param aFrame The frame whose transformation should be applied.
2923 : * @param aOrigin The delta from the frame origin to the coordinate space origin
2924 : * @param aBoundsOverride (optional) Force the frame bounds to be the
2925 : * specified bounds.
2926 : * @return The smallest rectangle containing the image of the transformed
2927 : * rectangle.
2928 : */
2929 0 : nsRect nsDisplayTransform::TransformRect(const nsRect &aUntransformedBounds,
2930 : const nsIFrame* aFrame,
2931 : const nsPoint &aOrigin,
2932 : const nsRect* aBoundsOverride)
2933 : {
2934 0 : NS_PRECONDITION(aFrame, "Can't take the transform based on a null frame!");
2935 :
2936 0 : float factor = nsPresContext::AppUnitsPerCSSPixel();
2937 : return nsLayoutUtils::MatrixTransformRect
2938 : (aUntransformedBounds,
2939 : GetResultingTransformMatrix(aFrame, aOrigin, factor, aBoundsOverride),
2940 0 : factor);
2941 : }
2942 :
2943 0 : nsRect nsDisplayTransform::TransformRectOut(const nsRect &aUntransformedBounds,
2944 : const nsIFrame* aFrame,
2945 : const nsPoint &aOrigin,
2946 : const nsRect* aBoundsOverride)
2947 : {
2948 0 : NS_PRECONDITION(aFrame, "Can't take the transform based on a null frame!");
2949 :
2950 0 : float factor = nsPresContext::AppUnitsPerCSSPixel();
2951 : return nsLayoutUtils::MatrixTransformRectOut
2952 : (aUntransformedBounds,
2953 : GetResultingTransformMatrix(aFrame, aOrigin, factor, aBoundsOverride),
2954 0 : factor);
2955 : }
2956 :
2957 0 : bool nsDisplayTransform::UntransformRectMatrix(const nsRect &aUntransformedBounds,
2958 : const gfx3DMatrix& aMatrix,
2959 : float aAppUnitsPerPixel,
2960 : nsRect *aOutRect)
2961 : {
2962 0 : if (aMatrix.IsSingular())
2963 0 : return false;
2964 :
2965 0 : gfxRect result(NSAppUnitsToFloatPixels(aUntransformedBounds.x, aAppUnitsPerPixel),
2966 0 : NSAppUnitsToFloatPixels(aUntransformedBounds.y, aAppUnitsPerPixel),
2967 0 : NSAppUnitsToFloatPixels(aUntransformedBounds.width, aAppUnitsPerPixel),
2968 0 : NSAppUnitsToFloatPixels(aUntransformedBounds.height, aAppUnitsPerPixel));
2969 :
2970 : /* We want to untransform the matrix, so invert the transformation first! */
2971 0 : result = aMatrix.Inverse().ProjectRectBounds(result);
2972 :
2973 0 : *aOutRect = nsLayoutUtils::RoundGfxRectToAppRect(result, aAppUnitsPerPixel);
2974 :
2975 0 : return true;
2976 : }
2977 :
2978 0 : bool nsDisplayTransform::UntransformRect(const nsRect &aUntransformedBounds,
2979 : const nsIFrame* aFrame,
2980 : const nsPoint &aOrigin,
2981 : nsRect* aOutRect)
2982 : {
2983 0 : NS_PRECONDITION(aFrame, "Can't take the transform based on a null frame!");
2984 :
2985 : /* Grab the matrix. If the transform is degenerate, just hand back the
2986 : * empty rect.
2987 : */
2988 0 : float factor = nsPresContext::AppUnitsPerCSSPixel();
2989 0 : gfx3DMatrix matrix = GetResultingTransformMatrix(aFrame, aOrigin, factor, nsnull);
2990 :
2991 0 : return UntransformRectMatrix(aUntransformedBounds, matrix, factor, aOutRect);
2992 : }
2993 :
2994 0 : nsDisplaySVGEffects::nsDisplaySVGEffects(nsDisplayListBuilder* aBuilder,
2995 : nsIFrame* aFrame, nsDisplayList* aList)
2996 : : nsDisplayWrapList(aBuilder, aFrame, aList), mEffectsFrame(aFrame),
2997 0 : mBounds(aFrame->GetVisualOverflowRectRelativeToSelf())
2998 : {
2999 0 : MOZ_COUNT_CTOR(nsDisplaySVGEffects);
3000 0 : }
3001 :
3002 : #ifdef NS_BUILD_REFCNT_LOGGING
3003 0 : nsDisplaySVGEffects::~nsDisplaySVGEffects()
3004 : {
3005 0 : MOZ_COUNT_DTOR(nsDisplaySVGEffects);
3006 0 : }
3007 : #endif
3008 :
3009 0 : nsRegion nsDisplaySVGEffects::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
3010 : bool* aForceTransparentSurface)
3011 : {
3012 0 : if (aForceTransparentSurface) {
3013 0 : *aForceTransparentSurface = false;
3014 : }
3015 0 : return nsRegion();
3016 : }
3017 :
3018 : void
3019 0 : nsDisplaySVGEffects::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
3020 : HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
3021 : {
3022 0 : nsPoint rectCenter(aRect.x + aRect.width / 2, aRect.y + aRect.height / 2);
3023 0 : if (nsSVGIntegrationUtils::HitTestFrameForEffects(mEffectsFrame,
3024 0 : rectCenter - aBuilder->ToReferenceFrame(mEffectsFrame))) {
3025 0 : mList.HitTest(aBuilder, aRect, aState, aOutFrames);
3026 : }
3027 0 : }
3028 :
3029 0 : void nsDisplaySVGEffects::Paint(nsDisplayListBuilder* aBuilder,
3030 : nsRenderingContext* aCtx)
3031 : {
3032 : nsSVGIntegrationUtils::PaintFramesWithEffects(aCtx,
3033 0 : mEffectsFrame, mVisibleRect, aBuilder, &mList);
3034 0 : }
3035 :
3036 0 : bool nsDisplaySVGEffects::ComputeVisibility(nsDisplayListBuilder* aBuilder,
3037 : nsRegion* aVisibleRegion,
3038 : const nsRect& aAllowVisibleRegionExpansion) {
3039 0 : nsPoint offset = aBuilder->ToReferenceFrame(mEffectsFrame);
3040 : nsRect dirtyRect =
3041 : nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(mEffectsFrame,
3042 0 : mVisibleRect - offset) +
3043 0 : offset;
3044 :
3045 : // Our children may be made translucent or arbitrarily deformed so we should
3046 : // not allow them to subtract area from aVisibleRegion.
3047 0 : nsRegion childrenVisible(dirtyRect);
3048 0 : nsRect r;
3049 0 : r.IntersectRect(dirtyRect, mList.GetBounds(aBuilder));
3050 0 : mList.ComputeVisibilityForSublist(aBuilder, &childrenVisible, r, nsRect());
3051 0 : return true;
3052 : }
3053 :
3054 0 : bool nsDisplaySVGEffects::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem)
3055 : {
3056 0 : if (aItem->GetType() != TYPE_SVG_EFFECTS)
3057 0 : return false;
3058 : // items for the same content element should be merged into a single
3059 : // compositing group
3060 : // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplaySVGEffects
3061 0 : if (aItem->GetUnderlyingFrame()->GetContent() != mFrame->GetContent())
3062 0 : return false;
3063 0 : nsDisplaySVGEffects* other = static_cast<nsDisplaySVGEffects*>(aItem);
3064 0 : mList.AppendToBottom(&other->mList);
3065 : mBounds.UnionRect(mBounds,
3066 0 : other->mBounds + other->mEffectsFrame->GetOffsetTo(mEffectsFrame));
3067 0 : return true;
3068 : }
3069 :
3070 : #ifdef MOZ_DUMP_PAINTING
3071 : void
3072 0 : nsDisplaySVGEffects::PrintEffects(FILE* aOutput)
3073 : {
3074 : nsIFrame* firstFrame =
3075 0 : nsLayoutUtils::GetFirstContinuationOrSpecialSibling(mEffectsFrame);
3076 : nsSVGEffects::EffectProperties effectProperties =
3077 0 : nsSVGEffects::GetEffectProperties(firstFrame);
3078 0 : bool isOK = true;
3079 0 : nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK);
3080 0 : bool first = true;
3081 0 : fprintf(aOutput, " effects=(");
3082 0 : if (mEffectsFrame->GetStyleDisplay()->mOpacity != 1.0f) {
3083 0 : first = false;
3084 0 : fprintf(aOutput, "opacity(%f)", mEffectsFrame->GetStyleDisplay()->mOpacity);
3085 : }
3086 0 : if (clipPathFrame) {
3087 0 : if (!first) {
3088 0 : fprintf(aOutput, ", ");
3089 : }
3090 0 : fprintf(aOutput, "clip(%s)", clipPathFrame->IsTrivial() ? "trivial" : "non-trivial");
3091 0 : first = false;
3092 : }
3093 0 : if (effectProperties.GetFilterFrame(&isOK)) {
3094 0 : if (!first) {
3095 0 : fprintf(aOutput, ", ");
3096 : }
3097 0 : fprintf(aOutput, "filter");
3098 0 : first = false;
3099 : }
3100 0 : if (effectProperties.GetMaskFrame(&isOK)) {
3101 0 : if (!first) {
3102 0 : fprintf(aOutput, ", ");
3103 : }
3104 0 : fprintf(aOutput, "mask");
3105 : }
3106 0 : fprintf(aOutput, ")");
3107 0 : }
3108 : #endif
3109 :
|