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 : return SnapBounds(mSnappingEnabled, mFrame->PresContext(),
1456 0 : nsRect(ToReferenceFrame(), mFrame->GetSize()));
1457 : }
1458 :
1459 : // Given a region, compute a conservative approximation to it as a list
1460 : // of rectangles that aren't vertically adjacent (i.e., vertically
1461 : // adjacent or overlapping rectangles are combined).
1462 : // Right now this is only approximate, some vertically overlapping rectangles
1463 : // aren't guaranteed to be combined.
1464 : static void
1465 0 : ComputeDisjointRectangles(const nsRegion& aRegion,
1466 : nsTArray<nsRect>* aRects) {
1467 0 : nscoord accumulationMargin = nsPresContext::CSSPixelsToAppUnits(25);
1468 0 : nsRect accumulated;
1469 0 : nsRegionRectIterator iter(aRegion);
1470 0 : while (true) {
1471 0 : const nsRect* r = iter.Next();
1472 0 : if (r && !accumulated.IsEmpty() &&
1473 0 : accumulated.YMost() >= r->y - accumulationMargin) {
1474 0 : accumulated.UnionRect(accumulated, *r);
1475 0 : continue;
1476 : }
1477 :
1478 0 : if (!accumulated.IsEmpty()) {
1479 0 : aRects->AppendElement(accumulated);
1480 0 : accumulated.SetEmpty();
1481 : }
1482 :
1483 0 : if (!r)
1484 : break;
1485 :
1486 0 : accumulated = *r;
1487 : }
1488 0 : }
1489 :
1490 : void
1491 0 : nsDisplayBoxShadowOuter::Paint(nsDisplayListBuilder* aBuilder,
1492 : nsRenderingContext* aCtx) {
1493 0 : nsPoint offset = ToReferenceFrame();
1494 0 : nsRect borderRect = nsRect(offset, mFrame->GetSize());
1495 0 : nsPresContext* presContext = mFrame->PresContext();
1496 0 : nsAutoTArray<nsRect,10> rects;
1497 0 : ComputeDisjointRectangles(mVisibleRegion, &rects);
1498 :
1499 0 : for (PRUint32 i = 0; i < rects.Length(); ++i) {
1500 0 : aCtx->PushState();
1501 0 : aCtx->IntersectClip(rects[i]);
1502 : nsCSSRendering::PaintBoxShadowOuter(presContext, *aCtx, mFrame,
1503 0 : borderRect, rects[i]);
1504 0 : aCtx->PopState();
1505 : }
1506 0 : }
1507 :
1508 : nsRect
1509 0 : nsDisplayBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder) {
1510 0 : return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
1511 : }
1512 :
1513 : bool
1514 0 : nsDisplayBoxShadowOuter::ComputeVisibility(nsDisplayListBuilder* aBuilder,
1515 : nsRegion* aVisibleRegion,
1516 : const nsRect& aAllowVisibleRegionExpansion) {
1517 0 : if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
1518 0 : aAllowVisibleRegionExpansion)) {
1519 0 : return false;
1520 : }
1521 :
1522 : // Store the actual visible region
1523 0 : mVisibleRegion.And(*aVisibleRegion, mVisibleRect);
1524 :
1525 0 : nsPoint origin = ToReferenceFrame();
1526 0 : nsRect visibleBounds = aVisibleRegion->GetBounds();
1527 0 : nsRect frameRect(origin, mFrame->GetSize());
1528 0 : if (!frameRect.Contains(visibleBounds))
1529 0 : return true;
1530 :
1531 : // the visible region is entirely inside the border-rect, and box shadows
1532 : // never render within the border-rect (unless there's a border radius).
1533 : nscoord twipsRadii[8];
1534 0 : bool hasBorderRadii = mFrame->GetBorderRadii(twipsRadii);
1535 0 : if (!hasBorderRadii)
1536 0 : return false;
1537 :
1538 0 : return !RoundedRectContainsRect(frameRect, twipsRadii, visibleBounds);
1539 : }
1540 :
1541 : void
1542 0 : nsDisplayBoxShadowInner::Paint(nsDisplayListBuilder* aBuilder,
1543 : nsRenderingContext* aCtx) {
1544 0 : nsPoint offset = ToReferenceFrame();
1545 0 : nsRect borderRect = nsRect(offset, mFrame->GetSize());
1546 0 : nsPresContext* presContext = mFrame->PresContext();
1547 0 : nsAutoTArray<nsRect,10> rects;
1548 0 : ComputeDisjointRectangles(mVisibleRegion, &rects);
1549 :
1550 0 : for (PRUint32 i = 0; i < rects.Length(); ++i) {
1551 0 : aCtx->PushState();
1552 0 : aCtx->IntersectClip(rects[i]);
1553 : nsCSSRendering::PaintBoxShadowInner(presContext, *aCtx, mFrame,
1554 0 : borderRect, rects[i]);
1555 0 : aCtx->PopState();
1556 : }
1557 0 : }
1558 :
1559 : bool
1560 0 : nsDisplayBoxShadowInner::ComputeVisibility(nsDisplayListBuilder* aBuilder,
1561 : nsRegion* aVisibleRegion,
1562 : const nsRect& aAllowVisibleRegionExpansion) {
1563 0 : if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
1564 0 : aAllowVisibleRegionExpansion)) {
1565 0 : return false;
1566 : }
1567 :
1568 : // Store the actual visible region
1569 0 : mVisibleRegion.And(*aVisibleRegion, mVisibleRect);
1570 0 : return true;
1571 : }
1572 :
1573 0 : nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
1574 : nsIFrame* aFrame, nsDisplayList* aList)
1575 0 : : nsDisplayItem(aBuilder, aFrame) {
1576 0 : mList.AppendToTop(aList);
1577 0 : }
1578 :
1579 0 : nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
1580 : nsIFrame* aFrame, nsDisplayItem* aItem)
1581 0 : : nsDisplayItem(aBuilder, aFrame) {
1582 0 : mList.AppendToTop(aItem);
1583 0 : }
1584 :
1585 0 : nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
1586 : nsIFrame* aFrame)
1587 0 : : nsDisplayItem(aBuilder, aFrame) {
1588 0 : }
1589 :
1590 0 : nsDisplayWrapList::~nsDisplayWrapList() {
1591 0 : mList.DeleteAll();
1592 0 : }
1593 :
1594 : void
1595 0 : nsDisplayWrapList::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
1596 : HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {
1597 0 : mList.HitTest(aBuilder, aRect, aState, aOutFrames);
1598 0 : }
1599 :
1600 : nsRect
1601 0 : nsDisplayWrapList::GetBounds(nsDisplayListBuilder* aBuilder) {
1602 0 : return mList.GetBounds(aBuilder);
1603 : }
1604 :
1605 : bool
1606 0 : nsDisplayWrapList::ComputeVisibility(nsDisplayListBuilder* aBuilder,
1607 : nsRegion* aVisibleRegion,
1608 : const nsRect& aAllowVisibleRegionExpansion) {
1609 : return mList.ComputeVisibilityForSublist(aBuilder, aVisibleRegion,
1610 : mVisibleRect,
1611 0 : aAllowVisibleRegionExpansion);
1612 : }
1613 :
1614 : nsRegion
1615 0 : nsDisplayWrapList::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
1616 : bool* aForceTransparentSurface) {
1617 0 : if (aForceTransparentSurface) {
1618 0 : *aForceTransparentSurface = false;
1619 : }
1620 0 : nsRegion result;
1621 0 : if (mList.IsOpaque()) {
1622 0 : result = GetBounds(aBuilder);
1623 : }
1624 : return result;
1625 : }
1626 :
1627 0 : bool nsDisplayWrapList::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) {
1628 : // We could try to do something but let's conservatively just return false.
1629 0 : return false;
1630 : }
1631 :
1632 0 : bool nsDisplayWrapList::IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
1633 : nsIFrame* aFrame) {
1634 0 : NS_WARNING("nsDisplayWrapList::IsVaryingRelativeToMovingFrame called unexpectedly");
1635 : // We could try to do something but let's conservatively just return true.
1636 0 : return true;
1637 : }
1638 :
1639 0 : void nsDisplayWrapList::Paint(nsDisplayListBuilder* aBuilder,
1640 : nsRenderingContext* aCtx) {
1641 0 : NS_ERROR("nsDisplayWrapList should have been flattened away for painting");
1642 0 : }
1643 :
1644 0 : bool nsDisplayWrapList::ChildrenCanBeInactive(nsDisplayListBuilder* aBuilder,
1645 : LayerManager* aManager,
1646 : const nsDisplayList& aList,
1647 : nsIFrame* aActiveScrolledRoot) {
1648 0 : for (nsDisplayItem* i = aList.GetBottom(); i; i = i->GetAbove()) {
1649 0 : nsIFrame* f = i->GetUnderlyingFrame();
1650 0 : if (f) {
1651 : nsIFrame* activeScrolledRoot =
1652 0 : nsLayoutUtils::GetActiveScrolledRootFor(f, nsnull);
1653 0 : if (activeScrolledRoot != aActiveScrolledRoot)
1654 0 : return false;
1655 : }
1656 :
1657 0 : LayerState state = i->GetLayerState(aBuilder, aManager);
1658 0 : if (state == LAYER_ACTIVE)
1659 0 : return false;
1660 0 : if (state == LAYER_NONE) {
1661 0 : nsDisplayList* list = i->GetList();
1662 0 : if (list && !ChildrenCanBeInactive(aBuilder, aManager, *list, aActiveScrolledRoot))
1663 0 : return false;
1664 : }
1665 : }
1666 0 : return true;
1667 : }
1668 :
1669 0 : nsRect nsDisplayWrapList::GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder)
1670 : {
1671 0 : nsRect bounds;
1672 0 : for (nsDisplayItem* i = mList.GetBottom(); i; i = i->GetAbove()) {
1673 0 : bounds.UnionRect(bounds, i->GetComponentAlphaBounds(aBuilder));
1674 : }
1675 : return bounds;
1676 : }
1677 :
1678 : static nsresult
1679 0 : WrapDisplayList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
1680 : nsDisplayList* aList, nsDisplayWrapper* aWrapper) {
1681 0 : if (!aList->GetTop())
1682 0 : return NS_OK;
1683 0 : nsDisplayItem* item = aWrapper->WrapList(aBuilder, aFrame, aList);
1684 0 : if (!item)
1685 0 : return NS_ERROR_OUT_OF_MEMORY;
1686 : // aList was emptied
1687 0 : aList->AppendToTop(item);
1688 0 : return NS_OK;
1689 : }
1690 :
1691 : static nsresult
1692 0 : WrapEachDisplayItem(nsDisplayListBuilder* aBuilder,
1693 : nsDisplayList* aList, nsDisplayWrapper* aWrapper) {
1694 0 : nsDisplayList newList;
1695 : nsDisplayItem* item;
1696 0 : while ((item = aList->RemoveBottom())) {
1697 0 : item = aWrapper->WrapItem(aBuilder, item);
1698 0 : if (!item)
1699 0 : return NS_ERROR_OUT_OF_MEMORY;
1700 0 : newList.AppendToTop(item);
1701 : }
1702 : // aList was emptied
1703 0 : aList->AppendToTop(&newList);
1704 0 : return NS_OK;
1705 : }
1706 :
1707 0 : nsresult nsDisplayWrapper::WrapLists(nsDisplayListBuilder* aBuilder,
1708 : nsIFrame* aFrame, const nsDisplayListSet& aIn, const nsDisplayListSet& aOut)
1709 : {
1710 0 : nsresult rv = WrapListsInPlace(aBuilder, aFrame, aIn);
1711 0 : NS_ENSURE_SUCCESS(rv, rv);
1712 :
1713 0 : if (&aOut == &aIn)
1714 0 : return NS_OK;
1715 0 : aOut.BorderBackground()->AppendToTop(aIn.BorderBackground());
1716 0 : aOut.BlockBorderBackgrounds()->AppendToTop(aIn.BlockBorderBackgrounds());
1717 0 : aOut.Floats()->AppendToTop(aIn.Floats());
1718 0 : aOut.Content()->AppendToTop(aIn.Content());
1719 0 : aOut.PositionedDescendants()->AppendToTop(aIn.PositionedDescendants());
1720 0 : aOut.Outlines()->AppendToTop(aIn.Outlines());
1721 0 : return NS_OK;
1722 : }
1723 :
1724 0 : nsresult nsDisplayWrapper::WrapListsInPlace(nsDisplayListBuilder* aBuilder,
1725 : nsIFrame* aFrame, const nsDisplayListSet& aLists)
1726 : {
1727 : nsresult rv;
1728 0 : if (WrapBorderBackground()) {
1729 : // Our border-backgrounds are in-flow
1730 0 : rv = WrapDisplayList(aBuilder, aFrame, aLists.BorderBackground(), this);
1731 0 : NS_ENSURE_SUCCESS(rv, rv);
1732 : }
1733 : // Our block border-backgrounds are in-flow
1734 0 : rv = WrapDisplayList(aBuilder, aFrame, aLists.BlockBorderBackgrounds(), this);
1735 0 : NS_ENSURE_SUCCESS(rv, rv);
1736 : // The floats are not in flow
1737 0 : rv = WrapEachDisplayItem(aBuilder, aLists.Floats(), this);
1738 0 : NS_ENSURE_SUCCESS(rv, rv);
1739 : // Our child content is in flow
1740 0 : rv = WrapDisplayList(aBuilder, aFrame, aLists.Content(), this);
1741 0 : NS_ENSURE_SUCCESS(rv, rv);
1742 : // The positioned descendants may not be in-flow
1743 0 : rv = WrapEachDisplayItem(aBuilder, aLists.PositionedDescendants(), this);
1744 0 : NS_ENSURE_SUCCESS(rv, rv);
1745 : // The outlines may not be in-flow
1746 0 : return WrapEachDisplayItem(aBuilder, aLists.Outlines(), this);
1747 : }
1748 :
1749 0 : nsDisplayOpacity::nsDisplayOpacity(nsDisplayListBuilder* aBuilder,
1750 : nsIFrame* aFrame, nsDisplayList* aList)
1751 0 : : nsDisplayWrapList(aBuilder, aFrame, aList) {
1752 0 : MOZ_COUNT_CTOR(nsDisplayOpacity);
1753 0 : }
1754 :
1755 : #ifdef NS_BUILD_REFCNT_LOGGING
1756 0 : nsDisplayOpacity::~nsDisplayOpacity() {
1757 0 : MOZ_COUNT_DTOR(nsDisplayOpacity);
1758 0 : }
1759 : #endif
1760 :
1761 0 : nsRegion nsDisplayOpacity::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
1762 : bool* aForceTransparentSurface) {
1763 0 : if (aForceTransparentSurface) {
1764 0 : *aForceTransparentSurface = false;
1765 : }
1766 : // We are never opaque, if our opacity was < 1 then we wouldn't have
1767 : // been created.
1768 0 : return nsRegion();
1769 : }
1770 :
1771 : // nsDisplayOpacity uses layers for rendering
1772 : already_AddRefed<Layer>
1773 0 : nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder,
1774 : LayerManager* aManager,
1775 : const ContainerParameters& aContainerParameters) {
1776 : nsRefPtr<Layer> layer = aBuilder->LayerBuilder()->
1777 : BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
1778 0 : aContainerParameters, nsnull);
1779 0 : if (!layer)
1780 0 : return nsnull;
1781 :
1782 0 : layer->SetOpacity(mFrame->GetStyleDisplay()->mOpacity);
1783 0 : return layer.forget();
1784 : }
1785 :
1786 : /**
1787 : * This doesn't take into account layer scaling --- the layer may be
1788 : * rendered at a higher (or lower) resolution, affecting the retained layer
1789 : * size --- but this should be good enough.
1790 : */
1791 : static bool
1792 0 : IsItemTooSmallForActiveLayer(nsDisplayItem* aItem)
1793 : {
1794 0 : nsIntRect visibleDevPixels = aItem->GetVisibleRect().ToOutsidePixels(
1795 0 : aItem->GetUnderlyingFrame()->PresContext()->AppUnitsPerDevPixel());
1796 : static const int MIN_ACTIVE_LAYER_SIZE_DEV_PIXELS = 16;
1797 : return visibleDevPixels.Size() <
1798 0 : nsIntSize(MIN_ACTIVE_LAYER_SIZE_DEV_PIXELS, MIN_ACTIVE_LAYER_SIZE_DEV_PIXELS);
1799 : }
1800 :
1801 : nsDisplayItem::LayerState
1802 0 : nsDisplayOpacity::GetLayerState(nsDisplayListBuilder* aBuilder,
1803 : LayerManager* aManager) {
1804 0 : if (mFrame->AreLayersMarkedActive(nsChangeHint_UpdateOpacityLayer) &&
1805 0 : !IsItemTooSmallForActiveLayer(this))
1806 0 : return LAYER_ACTIVE;
1807 : nsIFrame* activeScrolledRoot =
1808 0 : nsLayoutUtils::GetActiveScrolledRootFor(mFrame, nsnull);
1809 0 : return !ChildrenCanBeInactive(aBuilder, aManager, mList, activeScrolledRoot)
1810 0 : ? LAYER_ACTIVE : LAYER_INACTIVE;
1811 : }
1812 :
1813 : bool
1814 0 : nsDisplayOpacity::ComputeVisibility(nsDisplayListBuilder* aBuilder,
1815 : nsRegion* aVisibleRegion,
1816 : const nsRect& aAllowVisibleRegionExpansion) {
1817 : // Our children are translucent so we should not allow them to subtract
1818 : // area from aVisibleRegion. We do need to find out what is visible under
1819 : // our children in the temporary compositing buffer, because if our children
1820 : // paint our entire bounds opaquely then we don't need an alpha channel in
1821 : // the temporary compositing buffer.
1822 0 : nsRect bounds = GetBounds(aBuilder);
1823 0 : nsRegion visibleUnderChildren;
1824 0 : visibleUnderChildren.And(*aVisibleRegion, bounds);
1825 0 : nsRect allowExpansion;
1826 0 : allowExpansion.IntersectRect(bounds, aAllowVisibleRegionExpansion);
1827 : return
1828 : nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleUnderChildren,
1829 0 : allowExpansion);
1830 : }
1831 :
1832 0 : bool nsDisplayOpacity::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) {
1833 0 : if (aItem->GetType() != TYPE_OPACITY)
1834 0 : return false;
1835 : // items for the same content element should be merged into a single
1836 : // compositing group
1837 : // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity
1838 0 : if (aItem->GetUnderlyingFrame()->GetContent() != mFrame->GetContent())
1839 0 : return false;
1840 0 : mList.AppendToBottom(&static_cast<nsDisplayOpacity*>(aItem)->mList);
1841 0 : return true;
1842 : }
1843 :
1844 0 : nsDisplayOwnLayer::nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder,
1845 : nsIFrame* aFrame, nsDisplayList* aList)
1846 0 : : nsDisplayWrapList(aBuilder, aFrame, aList) {
1847 0 : MOZ_COUNT_CTOR(nsDisplayOwnLayer);
1848 0 : }
1849 :
1850 : #ifdef NS_BUILD_REFCNT_LOGGING
1851 0 : nsDisplayOwnLayer::~nsDisplayOwnLayer() {
1852 0 : MOZ_COUNT_DTOR(nsDisplayOwnLayer);
1853 0 : }
1854 : #endif
1855 :
1856 : // nsDisplayOpacity uses layers for rendering
1857 : already_AddRefed<Layer>
1858 0 : nsDisplayOwnLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
1859 : LayerManager* aManager,
1860 : const ContainerParameters& aContainerParameters) {
1861 : nsRefPtr<Layer> layer = aBuilder->LayerBuilder()->
1862 : BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
1863 0 : aContainerParameters, nsnull);
1864 0 : return layer.forget();
1865 : }
1866 :
1867 0 : nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder,
1868 : nsDisplayList* aList,
1869 : nsIFrame* aForFrame,
1870 : nsIFrame* aScrolledFrame,
1871 : nsIFrame* aScrollFrame)
1872 : : nsDisplayWrapList(aBuilder, aForFrame, aList)
1873 : , mScrollFrame(aScrollFrame)
1874 0 : , mScrolledFrame(aScrolledFrame)
1875 : {
1876 : #ifdef NS_BUILD_REFCNT_LOGGING
1877 0 : MOZ_COUNT_CTOR(nsDisplayScrollLayer);
1878 : #endif
1879 :
1880 0 : NS_ASSERTION(mScrolledFrame && mScrolledFrame->GetContent(),
1881 : "Need a child frame with content");
1882 0 : }
1883 :
1884 0 : nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder,
1885 : nsDisplayItem* aItem,
1886 : nsIFrame* aForFrame,
1887 : nsIFrame* aScrolledFrame,
1888 : nsIFrame* aScrollFrame)
1889 : : nsDisplayWrapList(aBuilder, aForFrame, aItem)
1890 : , mScrollFrame(aScrollFrame)
1891 0 : , mScrolledFrame(aScrolledFrame)
1892 : {
1893 : #ifdef NS_BUILD_REFCNT_LOGGING
1894 0 : MOZ_COUNT_CTOR(nsDisplayScrollLayer);
1895 : #endif
1896 :
1897 0 : NS_ASSERTION(mScrolledFrame && mScrolledFrame->GetContent(),
1898 : "Need a child frame with content");
1899 0 : }
1900 :
1901 0 : nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder,
1902 : nsIFrame* aForFrame,
1903 : nsIFrame* aScrolledFrame,
1904 : nsIFrame* aScrollFrame)
1905 : : nsDisplayWrapList(aBuilder, aForFrame)
1906 : , mScrollFrame(aScrollFrame)
1907 0 : , mScrolledFrame(aScrolledFrame)
1908 : {
1909 : #ifdef NS_BUILD_REFCNT_LOGGING
1910 0 : MOZ_COUNT_CTOR(nsDisplayScrollLayer);
1911 : #endif
1912 :
1913 0 : NS_ASSERTION(mScrolledFrame && mScrolledFrame->GetContent(),
1914 : "Need a child frame with content");
1915 0 : }
1916 :
1917 : #ifdef NS_BUILD_REFCNT_LOGGING
1918 0 : nsDisplayScrollLayer::~nsDisplayScrollLayer()
1919 : {
1920 0 : MOZ_COUNT_DTOR(nsDisplayScrollLayer);
1921 0 : }
1922 : #endif
1923 :
1924 : already_AddRefed<Layer>
1925 0 : nsDisplayScrollLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
1926 : LayerManager* aManager,
1927 : const ContainerParameters& aContainerParameters) {
1928 : nsRefPtr<ContainerLayer> layer = aBuilder->LayerBuilder()->
1929 : BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
1930 0 : aContainerParameters, nsnull);
1931 :
1932 : // Get the already set unique ID for scrolling this content remotely.
1933 : // Or, if not set, generate a new ID.
1934 0 : nsIContent* content = mScrolledFrame->GetContent();
1935 0 : ViewID scrollId = nsLayoutUtils::FindIDFor(content);
1936 :
1937 0 : nsRect viewport = mScrollFrame->GetRect() -
1938 0 : mScrollFrame->GetPosition() +
1939 0 : aBuilder->ToReferenceFrame(mScrollFrame);
1940 :
1941 0 : bool usingDisplayport = false;
1942 0 : nsRect displayport;
1943 0 : if (content) {
1944 0 : usingDisplayport = nsLayoutUtils::GetDisplayPort(content, &displayport);
1945 : }
1946 : RecordFrameMetrics(mScrolledFrame, mScrollFrame, layer, mVisibleRect, viewport,
1947 : (usingDisplayport ? &displayport : nsnull), scrollId,
1948 0 : aContainerParameters);
1949 :
1950 0 : return layer.forget();
1951 : }
1952 :
1953 : bool
1954 0 : nsDisplayScrollLayer::ComputeVisibility(nsDisplayListBuilder* aBuilder,
1955 : nsRegion* aVisibleRegion,
1956 : const nsRect& aAllowVisibleRegionExpansion)
1957 : {
1958 0 : nsRect displayport;
1959 0 : if (nsLayoutUtils::GetDisplayPort(mScrolledFrame->GetContent(), &displayport)) {
1960 : // The visible region for the children may be much bigger than the hole we
1961 : // are viewing the children from, so that the compositor process has enough
1962 : // content to asynchronously pan while content is being refreshed.
1963 :
1964 0 : nsRegion childVisibleRegion = displayport + aBuilder->ToReferenceFrame(mScrollFrame);
1965 :
1966 0 : nsRect boundedRect;
1967 0 : boundedRect.IntersectRect(childVisibleRegion.GetBounds(), mList.GetBounds(aBuilder));
1968 0 : nsRect allowExpansion;
1969 0 : allowExpansion.IntersectRect(allowExpansion, boundedRect);
1970 : bool visible = mList.ComputeVisibilityForSublist(
1971 0 : aBuilder, &childVisibleRegion, boundedRect, allowExpansion);
1972 0 : mVisibleRect = boundedRect;
1973 :
1974 0 : return visible;
1975 :
1976 : } else {
1977 : return nsDisplayWrapList::ComputeVisibility(aBuilder, aVisibleRegion,
1978 0 : aAllowVisibleRegionExpansion);
1979 : }
1980 : }
1981 :
1982 : LayerState
1983 0 : nsDisplayScrollLayer::GetLayerState(nsDisplayListBuilder* aBuilder,
1984 : LayerManager* aManager)
1985 : {
1986 : // Force this as a layer so we can scroll asynchronously.
1987 : // This causes incorrect rendering for rounded clips!
1988 0 : return LAYER_ACTIVE_FORCE;
1989 : }
1990 :
1991 : bool
1992 0 : nsDisplayScrollLayer::TryMerge(nsDisplayListBuilder* aBuilder,
1993 : nsDisplayItem* aItem)
1994 : {
1995 0 : if (aItem->GetType() != TYPE_SCROLL_LAYER) {
1996 0 : return false;
1997 : }
1998 :
1999 0 : nsDisplayScrollLayer* other = static_cast<nsDisplayScrollLayer*>(aItem);
2000 0 : if (other->mScrolledFrame != this->mScrolledFrame) {
2001 0 : return false;
2002 : }
2003 :
2004 0 : FrameProperties props = mScrolledFrame->Properties();
2005 : props.Set(nsIFrame::ScrollLayerCount(),
2006 0 : reinterpret_cast<void*>(GetScrollLayerCount() - 1));
2007 :
2008 0 : mList.AppendToBottom(&other->mList);
2009 : // XXX - This ensures that the frame associated with a scroll layer after
2010 : // merging is the first, rather than the last. This tends to change less,
2011 : // ensuring we're more likely to retain the associated gfx layer.
2012 : // See Bug 729534 and Bug 731641.
2013 0 : mFrame = other->mFrame;
2014 0 : return true;
2015 : }
2016 :
2017 : bool
2018 0 : nsDisplayScrollLayer::ShouldFlattenAway(nsDisplayListBuilder* aBuilder)
2019 : {
2020 0 : return GetScrollLayerCount() > 1;
2021 : }
2022 :
2023 : PRWord
2024 0 : nsDisplayScrollLayer::GetScrollLayerCount()
2025 : {
2026 0 : FrameProperties props = mScrolledFrame->Properties();
2027 : #ifdef DEBUG
2028 0 : bool hasCount = false;
2029 : PRWord result = reinterpret_cast<PRWord>(
2030 0 : props.Get(nsIFrame::ScrollLayerCount(), &hasCount));
2031 : // If this aborts, then the property was either not added before scroll
2032 : // layers were created or the property was deleted to early. If the latter,
2033 : // make sure that nsDisplayScrollInfoLayer is on the bottom of the list so
2034 : // that it is processed last.
2035 0 : NS_ABORT_IF_FALSE(hasCount, "nsDisplayScrollLayer should always be defined");
2036 0 : return result;
2037 : #else
2038 : return reinterpret_cast<PRWord>(props.Get(nsIFrame::ScrollLayerCount()));
2039 : #endif
2040 : }
2041 :
2042 : PRWord
2043 0 : nsDisplayScrollLayer::RemoveScrollLayerCount()
2044 : {
2045 0 : PRWord result = GetScrollLayerCount();
2046 0 : FrameProperties props = mScrolledFrame->Properties();
2047 0 : props.Remove(nsIFrame::ScrollLayerCount());
2048 0 : return result;
2049 : }
2050 :
2051 :
2052 0 : nsDisplayScrollInfoLayer::nsDisplayScrollInfoLayer(
2053 : nsDisplayListBuilder* aBuilder,
2054 : nsIFrame* aScrolledFrame,
2055 : nsIFrame* aScrollFrame)
2056 0 : : nsDisplayScrollLayer(aBuilder, aScrolledFrame, aScrolledFrame, aScrollFrame)
2057 : {
2058 : #ifdef NS_BUILD_REFCNT_LOGGING
2059 0 : MOZ_COUNT_CTOR(nsDisplayScrollInfoLayer);
2060 : #endif
2061 0 : }
2062 :
2063 : #ifdef NS_BUILD_REFCNT_LOGGING
2064 0 : nsDisplayScrollInfoLayer::~nsDisplayScrollInfoLayer()
2065 : {
2066 0 : MOZ_COUNT_DTOR(nsDisplayScrollInfoLayer);
2067 0 : }
2068 : #endif
2069 :
2070 : LayerState
2071 0 : nsDisplayScrollInfoLayer::GetLayerState(nsDisplayListBuilder* aBuilder,
2072 : LayerManager* aManager)
2073 : {
2074 0 : return LAYER_ACTIVE_EMPTY;
2075 : }
2076 :
2077 : bool
2078 0 : nsDisplayScrollInfoLayer::TryMerge(nsDisplayListBuilder* aBuilder,
2079 : nsDisplayItem* aItem)
2080 : {
2081 0 : return false;
2082 : }
2083 :
2084 : bool
2085 0 : nsDisplayScrollInfoLayer::ShouldFlattenAway(nsDisplayListBuilder* aBuilder)
2086 : {
2087 : // Layer metadata for a particular scroll frame needs to be unique. Only
2088 : // one nsDisplayScrollLayer (with rendered content) or one
2089 : // nsDisplayScrollInfoLayer (with only the metadata) should survive the
2090 : // visibility computation.
2091 0 : return RemoveScrollLayerCount() == 1;
2092 : }
2093 :
2094 0 : nsDisplayClip::nsDisplayClip(nsDisplayListBuilder* aBuilder,
2095 : nsIFrame* aFrame, nsDisplayItem* aItem,
2096 : const nsRect& aRect)
2097 0 : : nsDisplayWrapList(aBuilder, aFrame, aItem) {
2098 0 : MOZ_COUNT_CTOR(nsDisplayClip);
2099 0 : mClip = SnapBounds(aBuilder->IsSnappingEnabled() && !aBuilder->IsInTransform(),
2100 0 : aBuilder->CurrentPresContext(), aRect);
2101 0 : }
2102 :
2103 0 : nsDisplayClip::nsDisplayClip(nsDisplayListBuilder* aBuilder,
2104 : nsIFrame* aFrame, nsDisplayList* aList,
2105 : const nsRect& aRect)
2106 0 : : nsDisplayWrapList(aBuilder, aFrame, aList) {
2107 0 : MOZ_COUNT_CTOR(nsDisplayClip);
2108 0 : mClip = SnapBounds(aBuilder->IsSnappingEnabled() && !aBuilder->IsInTransform(),
2109 0 : aBuilder->CurrentPresContext(), aRect);
2110 0 : }
2111 :
2112 0 : nsRect nsDisplayClip::GetBounds(nsDisplayListBuilder* aBuilder) {
2113 0 : nsRect r = nsDisplayWrapList::GetBounds(aBuilder);
2114 0 : r.IntersectRect(mClip, r);
2115 : return r;
2116 : }
2117 :
2118 : #ifdef NS_BUILD_REFCNT_LOGGING
2119 0 : nsDisplayClip::~nsDisplayClip() {
2120 0 : MOZ_COUNT_DTOR(nsDisplayClip);
2121 0 : }
2122 : #endif
2123 :
2124 0 : void nsDisplayClip::Paint(nsDisplayListBuilder* aBuilder,
2125 : nsRenderingContext* aCtx) {
2126 0 : NS_ERROR("nsDisplayClip should have been flattened away for painting");
2127 0 : }
2128 :
2129 0 : bool nsDisplayClip::ComputeVisibility(nsDisplayListBuilder* aBuilder,
2130 : nsRegion* aVisibleRegion,
2131 : const nsRect& aAllowVisibleRegionExpansion) {
2132 0 : nsRegion clipped;
2133 0 : clipped.And(*aVisibleRegion, mClip);
2134 :
2135 0 : nsRegion finalClipped(clipped);
2136 0 : nsRect allowExpansion;
2137 0 : allowExpansion.IntersectRect(mClip, aAllowVisibleRegionExpansion);
2138 : bool anyVisible =
2139 : nsDisplayWrapList::ComputeVisibility(aBuilder, &finalClipped,
2140 0 : allowExpansion);
2141 :
2142 0 : nsRegion removed;
2143 0 : removed.Sub(clipped, finalClipped);
2144 0 : aBuilder->SubtractFromVisibleRegion(aVisibleRegion, removed);
2145 :
2146 0 : return anyVisible;
2147 : }
2148 :
2149 0 : bool nsDisplayClip::TryMerge(nsDisplayListBuilder* aBuilder,
2150 : nsDisplayItem* aItem) {
2151 0 : if (aItem->GetType() != TYPE_CLIP)
2152 0 : return false;
2153 0 : nsDisplayClip* other = static_cast<nsDisplayClip*>(aItem);
2154 0 : if (!other->mClip.IsEqualInterior(mClip))
2155 0 : return false;
2156 0 : mList.AppendToBottom(&other->mList);
2157 0 : return true;
2158 : }
2159 :
2160 0 : nsDisplayWrapList* nsDisplayClip::WrapWithClone(nsDisplayListBuilder* aBuilder,
2161 : nsDisplayItem* aItem) {
2162 : return new (aBuilder)
2163 0 : nsDisplayClip(aBuilder, aItem->GetUnderlyingFrame(), aItem, mClip);
2164 : }
2165 :
2166 0 : nsDisplayClipRoundedRect::nsDisplayClipRoundedRect(
2167 : nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
2168 : nsDisplayItem* aItem,
2169 : const nsRect& aRect, nscoord aRadii[8])
2170 0 : : nsDisplayClip(aBuilder, aFrame, aItem, aRect)
2171 : {
2172 0 : MOZ_COUNT_CTOR(nsDisplayClipRoundedRect);
2173 0 : memcpy(mRadii, aRadii, sizeof(mRadii));
2174 0 : }
2175 :
2176 0 : nsDisplayClipRoundedRect::nsDisplayClipRoundedRect(
2177 : nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
2178 : nsDisplayList* aList,
2179 : const nsRect& aRect, nscoord aRadii[8])
2180 0 : : nsDisplayClip(aBuilder, aFrame, aList, aRect)
2181 : {
2182 0 : MOZ_COUNT_CTOR(nsDisplayClipRoundedRect);
2183 0 : memcpy(mRadii, aRadii, sizeof(mRadii));
2184 0 : }
2185 :
2186 : #ifdef NS_BUILD_REFCNT_LOGGING
2187 0 : nsDisplayClipRoundedRect::~nsDisplayClipRoundedRect()
2188 : {
2189 0 : MOZ_COUNT_DTOR(nsDisplayClipRoundedRect);
2190 0 : }
2191 : #endif
2192 :
2193 : nsRegion
2194 0 : nsDisplayClipRoundedRect::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
2195 : bool* aForceTransparentSurface)
2196 : {
2197 0 : if (aForceTransparentSurface) {
2198 0 : *aForceTransparentSurface = false;
2199 : }
2200 0 : return nsRegion();
2201 : }
2202 :
2203 : void
2204 0 : nsDisplayClipRoundedRect::HitTest(nsDisplayListBuilder* aBuilder,
2205 : const nsRect& aRect, HitTestState* aState,
2206 : nsTArray<nsIFrame*> *aOutFrames)
2207 : {
2208 0 : if (!RoundedRectIntersectsRect(mClip, mRadii, aRect)) {
2209 : // aRect doesn't intersect our border-radius curve.
2210 :
2211 : // FIXME: This isn't quite sufficient for aRect having nontrivial
2212 : // size (which is the unusual case here), since it's possible that
2213 : // the part of aRect that intersects the the rounded rect isn't the
2214 : // part that intersects the items in mList.
2215 0 : return;
2216 : }
2217 :
2218 0 : mList.HitTest(aBuilder, aRect, aState, aOutFrames);
2219 : }
2220 :
2221 : nsDisplayWrapList*
2222 0 : nsDisplayClipRoundedRect::WrapWithClone(nsDisplayListBuilder* aBuilder,
2223 : nsDisplayItem* aItem) {
2224 : return new (aBuilder)
2225 : nsDisplayClipRoundedRect(aBuilder, aItem->GetUnderlyingFrame(), aItem,
2226 0 : mClip, mRadii);
2227 : }
2228 :
2229 0 : bool nsDisplayClipRoundedRect::ComputeVisibility(
2230 : nsDisplayListBuilder* aBuilder,
2231 : nsRegion* aVisibleRegion,
2232 : const nsRect& aAllowVisibleRegionExpansion)
2233 : {
2234 0 : nsRegion clipped;
2235 0 : clipped.And(*aVisibleRegion, mClip);
2236 :
2237 0 : return nsDisplayWrapList::ComputeVisibility(aBuilder, &clipped, nsRect());
2238 : // FIXME: Remove a *conservative* opaque region from aVisibleRegion
2239 : // (like in nsDisplayClip::ComputeVisibility).
2240 : }
2241 :
2242 0 : bool nsDisplayClipRoundedRect::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem)
2243 : {
2244 0 : if (aItem->GetType() != TYPE_CLIP_ROUNDED_RECT)
2245 0 : return false;
2246 : nsDisplayClipRoundedRect* other =
2247 0 : static_cast<nsDisplayClipRoundedRect*>(aItem);
2248 0 : if (!mClip.IsEqualInterior(other->mClip) ||
2249 0 : memcmp(mRadii, other->mRadii, sizeof(mRadii)) != 0)
2250 0 : return false;
2251 0 : mList.AppendToBottom(&other->mList);
2252 0 : return true;
2253 : }
2254 :
2255 0 : nsDisplayZoom::nsDisplayZoom(nsDisplayListBuilder* aBuilder,
2256 : nsIFrame* aFrame, nsDisplayList* aList,
2257 : PRInt32 aAPD, PRInt32 aParentAPD)
2258 : : nsDisplayOwnLayer(aBuilder, aFrame, aList), mAPD(aAPD),
2259 0 : mParentAPD(aParentAPD) {
2260 0 : MOZ_COUNT_CTOR(nsDisplayZoom);
2261 0 : }
2262 :
2263 : #ifdef NS_BUILD_REFCNT_LOGGING
2264 0 : nsDisplayZoom::~nsDisplayZoom() {
2265 0 : MOZ_COUNT_DTOR(nsDisplayZoom);
2266 0 : }
2267 : #endif
2268 :
2269 0 : nsRect nsDisplayZoom::GetBounds(nsDisplayListBuilder* aBuilder)
2270 : {
2271 0 : nsRect bounds = nsDisplayWrapList::GetBounds(aBuilder);
2272 0 : return bounds.ConvertAppUnitsRoundOut(mAPD, mParentAPD);
2273 : }
2274 :
2275 0 : void nsDisplayZoom::HitTest(nsDisplayListBuilder *aBuilder,
2276 : const nsRect& aRect,
2277 : HitTestState *aState,
2278 : nsTArray<nsIFrame*> *aOutFrames)
2279 : {
2280 0 : nsRect rect;
2281 : // A 1x1 rect indicates we are just hit testing a point, so pass down a 1x1
2282 : // rect as well instead of possibly rounding the width or height to zero.
2283 0 : if (aRect.width == 1 && aRect.height == 1) {
2284 0 : rect.MoveTo(aRect.TopLeft().ConvertAppUnits(mParentAPD, mAPD));
2285 0 : rect.width = rect.height = 1;
2286 : } else {
2287 0 : rect = aRect.ConvertAppUnitsRoundOut(mParentAPD, mAPD);
2288 : }
2289 0 : mList.HitTest(aBuilder, rect, aState, aOutFrames);
2290 0 : }
2291 :
2292 0 : void nsDisplayZoom::Paint(nsDisplayListBuilder* aBuilder,
2293 : nsRenderingContext* aCtx)
2294 : {
2295 0 : mList.PaintForFrame(aBuilder, aCtx, mFrame, nsDisplayList::PAINT_DEFAULT);
2296 0 : }
2297 :
2298 0 : bool nsDisplayZoom::ComputeVisibility(nsDisplayListBuilder *aBuilder,
2299 : nsRegion *aVisibleRegion,
2300 : const nsRect& aAllowVisibleRegionExpansion)
2301 : {
2302 : // Convert the passed in visible region to our appunits.
2303 : nsRegion visibleRegion =
2304 0 : aVisibleRegion->ConvertAppUnitsRoundOut(mParentAPD, mAPD);
2305 0 : nsRegion originalVisibleRegion = visibleRegion;
2306 :
2307 : nsRect transformedVisibleRect =
2308 0 : mVisibleRect.ConvertAppUnitsRoundOut(mParentAPD, mAPD);
2309 : nsRect allowExpansion =
2310 0 : aAllowVisibleRegionExpansion.ConvertAppUnitsRoundIn(mParentAPD, mAPD);
2311 : bool retval =
2312 : mList.ComputeVisibilityForSublist(aBuilder, &visibleRegion,
2313 : transformedVisibleRect,
2314 0 : allowExpansion);
2315 :
2316 0 : nsRegion removed;
2317 : // removed = originalVisibleRegion - visibleRegion
2318 0 : removed.Sub(originalVisibleRegion, visibleRegion);
2319 : // Convert removed region to parent appunits.
2320 0 : removed = removed.ConvertAppUnitsRoundIn(mAPD, mParentAPD);
2321 : // aVisibleRegion = aVisibleRegion - removed (modulo any simplifications
2322 : // SubtractFromVisibleRegion does)
2323 0 : aBuilder->SubtractFromVisibleRegion(aVisibleRegion, removed);
2324 :
2325 0 : return retval;
2326 : }
2327 :
2328 : ///////////////////////////////////////////////////
2329 : // nsDisplayTransform Implementation
2330 : //
2331 :
2332 : // Write #define UNIFIED_CONTINUATIONS here to have the transform property try
2333 : // to transform content with continuations as one unified block instead of
2334 : // several smaller ones. This is currently disabled because it doesn't work
2335 : // correctly, since when the frames are initially being reflowed, their
2336 : // continuations all compute their bounding rects independently of each other
2337 : // and consequently get the wrong value. Write #define DEBUG_HIT here to have
2338 : // the nsDisplayTransform class dump out a bunch of information about hit
2339 : // detection.
2340 : #undef UNIFIED_CONTINUATIONS
2341 : #undef DEBUG_HIT
2342 :
2343 : /* Returns the bounds of a frame as defined for transforms. If
2344 : * UNIFIED_CONTINUATIONS is not defined, this is simply the frame's bounding
2345 : * rectangle, translated to the origin. Otherwise, returns the smallest
2346 : * rectangle containing a frame and all of its continuations. For example, if
2347 : * there is a <span> element with several continuations split over several
2348 : * lines, this function will return the rectangle containing all of those
2349 : * continuations. This rectangle is relative to the origin of the frame's local
2350 : * coordinate space.
2351 : */
2352 : #ifndef UNIFIED_CONTINUATIONS
2353 :
2354 : nsRect
2355 0 : nsDisplayTransform::GetFrameBoundsForTransform(const nsIFrame* aFrame)
2356 : {
2357 0 : NS_PRECONDITION(aFrame, "Can't get the bounds of a nonexistent frame!");
2358 0 : return nsRect(nsPoint(0, 0), aFrame->GetSize());
2359 : }
2360 :
2361 : #else
2362 :
2363 : nsRect
2364 : nsDisplayTransform::GetFrameBoundsForTransform(const nsIFrame* aFrame)
2365 : {
2366 : NS_PRECONDITION(aFrame, "Can't get the bounds of a nonexistent frame!");
2367 :
2368 : nsRect result;
2369 :
2370 : /* Iterate through the continuation list, unioning together all the
2371 : * bounding rects.
2372 : */
2373 : for (const nsIFrame *currFrame = aFrame->GetFirstContinuation();
2374 : currFrame != nsnull;
2375 : currFrame = currFrame->GetNextContinuation())
2376 : {
2377 : /* Get the frame rect in local coordinates, then translate back to the
2378 : * original coordinates.
2379 : */
2380 : result.UnionRect(result, nsRect(currFrame->GetOffsetTo(aFrame),
2381 : currFrame->GetSize()));
2382 : }
2383 :
2384 : return result;
2385 : }
2386 :
2387 : #endif
2388 :
2389 : /* Returns the delta specified by the -moz-transform-origin property.
2390 : * This is a positive delta, meaning that it indicates the direction to move
2391 : * to get from (0, 0) of the frame to the transform origin.
2392 : */
2393 : static
2394 0 : gfxPoint3D GetDeltaToMozTransformOrigin(const nsIFrame* aFrame,
2395 : float aAppUnitsPerPixel,
2396 : const nsRect* aBoundsOverride)
2397 : {
2398 0 : NS_PRECONDITION(aFrame, "Can't get delta for a null frame!");
2399 0 : NS_PRECONDITION(aFrame->GetStyleDisplay()->HasTransform(),
2400 : "Can't get a delta for an untransformed frame!");
2401 :
2402 : /* For both of the coordinates, if the value of -moz-transform is a
2403 : * percentage, it's relative to the size of the frame. Otherwise, if it's
2404 : * a distance, it's already computed for us!
2405 : */
2406 0 : const nsStyleDisplay* display = aFrame->GetStyleDisplay();
2407 : nsRect boundingRect = (aBoundsOverride ? *aBoundsOverride :
2408 0 : nsDisplayTransform::GetFrameBoundsForTransform(aFrame));
2409 :
2410 : /* Allows us to access named variables by index. */
2411 0 : gfxPoint3D result;
2412 0 : gfxFloat* coords[3] = {&result.x, &result.y, &result.z};
2413 : const nscoord* dimensions[2] =
2414 0 : {&boundingRect.width, &boundingRect.height};
2415 :
2416 0 : for (PRUint8 index = 0; index < 2; ++index) {
2417 : /* If the -moz-transform-origin specifies a percentage, take the percentage
2418 : * of the size of the box.
2419 : */
2420 0 : const nsStyleCoord &coord = display->mTransformOrigin[index];
2421 0 : if (coord.GetUnit() == eStyleUnit_Calc) {
2422 0 : const nsStyleCoord::Calc *calc = coord.GetCalcValue();
2423 0 : *coords[index] =
2424 0 : NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) *
2425 : calc->mPercent +
2426 0 : NSAppUnitsToFloatPixels(calc->mLength, aAppUnitsPerPixel);
2427 0 : } else if (coord.GetUnit() == eStyleUnit_Percent) {
2428 0 : *coords[index] =
2429 0 : NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) *
2430 0 : coord.GetPercentValue();
2431 : } else {
2432 0 : NS_ABORT_IF_FALSE(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
2433 0 : *coords[index] =
2434 0 : NSAppUnitsToFloatPixels(coord.GetCoordValue(), aAppUnitsPerPixel);
2435 : }
2436 : }
2437 :
2438 0 : *coords[2] = NSAppUnitsToFloatPixels(display->mTransformOrigin[2].GetCoordValue(),
2439 0 : aAppUnitsPerPixel);
2440 : /* Adjust based on the origin of the rectangle. */
2441 0 : result.x += NSAppUnitsToFloatPixels(boundingRect.x, aAppUnitsPerPixel);
2442 0 : result.y += NSAppUnitsToFloatPixels(boundingRect.y, aAppUnitsPerPixel);
2443 :
2444 : return result;
2445 : }
2446 :
2447 : /* Returns the delta specified by the -moz-perspective-origin property.
2448 : * This is a positive delta, meaning that it indicates the direction to move
2449 : * to get from (0, 0) of the frame to the perspective origin.
2450 : */
2451 : static
2452 0 : gfxPoint3D GetDeltaToMozPerspectiveOrigin(const nsIFrame* aFrame,
2453 : float aAppUnitsPerPixel)
2454 : {
2455 0 : NS_PRECONDITION(aFrame, "Can't get delta for a null frame!");
2456 0 : NS_PRECONDITION(aFrame->GetStyleDisplay()->HasTransform(),
2457 : "Can't get a delta for an untransformed frame!");
2458 0 : NS_PRECONDITION(aFrame->GetParentStyleContextFrame(),
2459 : "Can't get delta without a style parent!");
2460 :
2461 : /* For both of the coordinates, if the value of -moz-perspective-origin is a
2462 : * percentage, it's relative to the size of the frame. Otherwise, if it's
2463 : * a distance, it's already computed for us!
2464 : */
2465 :
2466 : //TODO: Should this be using our bounds or the parent's bounds?
2467 : // How do we handle aBoundsOverride in the latter case?
2468 0 : nsIFrame* parent = aFrame->GetParentStyleContextFrame();
2469 0 : const nsStyleDisplay* display = aFrame->GetParent()->GetStyleDisplay();
2470 0 : nsRect boundingRect = nsDisplayTransform::GetFrameBoundsForTransform(parent);
2471 :
2472 : /* Allows us to access named variables by index. */
2473 0 : gfxPoint3D result;
2474 0 : result.z = 0.0f;
2475 0 : gfxFloat* coords[2] = {&result.x, &result.y};
2476 : const nscoord* dimensions[2] =
2477 0 : {&boundingRect.width, &boundingRect.height};
2478 :
2479 0 : for (PRUint8 index = 0; index < 2; ++index) {
2480 : /* If the -moz-transform-origin specifies a percentage, take the percentage
2481 : * of the size of the box.
2482 : */
2483 0 : const nsStyleCoord &coord = display->mPerspectiveOrigin[index];
2484 0 : if (coord.GetUnit() == eStyleUnit_Calc) {
2485 0 : const nsStyleCoord::Calc *calc = coord.GetCalcValue();
2486 0 : *coords[index] =
2487 0 : NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) *
2488 : calc->mPercent +
2489 0 : NSAppUnitsToFloatPixels(calc->mLength, aAppUnitsPerPixel);
2490 0 : } else if (coord.GetUnit() == eStyleUnit_Percent) {
2491 0 : *coords[index] =
2492 0 : NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) *
2493 0 : coord.GetPercentValue();
2494 : } else {
2495 0 : NS_ABORT_IF_FALSE(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
2496 0 : *coords[index] =
2497 0 : NSAppUnitsToFloatPixels(coord.GetCoordValue(), aAppUnitsPerPixel);
2498 : }
2499 : }
2500 :
2501 0 : nsPoint parentOffset = aFrame->GetOffsetTo(parent);
2502 : gfxPoint3D gfxOffset(
2503 0 : NSAppUnitsToFloatPixels(parentOffset.x, aAppUnitsPerPixel),
2504 0 : NSAppUnitsToFloatPixels(parentOffset.y, aAppUnitsPerPixel),
2505 0 : 0.0f);
2506 :
2507 0 : return result - gfxOffset;
2508 : }
2509 :
2510 : /* Wraps up the -moz-transform matrix in a change-of-basis matrix pair that
2511 : * translates from local coordinate space to transform coordinate space, then
2512 : * hands it back.
2513 : */
2514 : gfx3DMatrix
2515 0 : nsDisplayTransform::GetResultingTransformMatrix(const nsIFrame* aFrame,
2516 : const nsPoint &aOrigin,
2517 : float aAppUnitsPerPixel,
2518 : const nsRect* aBoundsOverride,
2519 : nsIFrame** aOutAncestor)
2520 : {
2521 0 : NS_PRECONDITION(aFrame, "Cannot get transform matrix for a null frame!");
2522 :
2523 0 : if (aOutAncestor) {
2524 0 : *aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
2525 : }
2526 :
2527 : /* Account for the -moz-transform-origin property by translating the
2528 : * coordinate space to the new origin.
2529 : */
2530 : gfxPoint3D toMozOrigin =
2531 0 : GetDeltaToMozTransformOrigin(aFrame, aAppUnitsPerPixel, aBoundsOverride);
2532 : gfxPoint3D newOrigin =
2533 0 : gfxPoint3D(NSAppUnitsToFloatPixels(aOrigin.x, aAppUnitsPerPixel),
2534 0 : NSAppUnitsToFloatPixels(aOrigin.y, aAppUnitsPerPixel),
2535 0 : 0.0f);
2536 :
2537 : /* Get the underlying transform matrix. This requires us to get the
2538 : * bounds of the frame.
2539 : */
2540 0 : const nsStyleDisplay* disp = aFrame->GetStyleDisplay();
2541 : nsRect bounds = (aBoundsOverride ? *aBoundsOverride :
2542 0 : nsDisplayTransform::GetFrameBoundsForTransform(aFrame));
2543 :
2544 : /* Get the matrix, then change its basis to factor in the origin. */
2545 : bool dummy;
2546 0 : gfx3DMatrix result;
2547 : /* Transformed frames always have a transform, or are preserving 3d (and might still have perspective!) */
2548 0 : if (disp->mSpecifiedTransform) {
2549 : result = nsStyleTransformMatrix::ReadTransforms(disp->mSpecifiedTransform,
2550 : aFrame->GetStyleContext(),
2551 : aFrame->PresContext(),
2552 0 : dummy, bounds, aAppUnitsPerPixel);
2553 : } else {
2554 0 : NS_ASSERTION(aFrame->GetStyleDisplay()->mTransformStyle == NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D ||
2555 : aFrame->GetStyleDisplay()->mBackfaceVisibility == NS_STYLE_BACKFACE_VISIBILITY_HIDDEN,
2556 : "If we don't have a transform, then we must have another reason to have an nsDisplayTransform created");
2557 : }
2558 :
2559 0 : const nsStyleDisplay* parentDisp = nsnull;
2560 0 : nsStyleContext* parentStyleContext = aFrame->GetStyleContext()->GetParent();
2561 0 : if (parentStyleContext) {
2562 0 : parentDisp = parentStyleContext->GetStyleDisplay();
2563 : }
2564 0 : if (nsLayoutUtils::Are3DTransformsEnabled() &&
2565 0 : parentDisp && parentDisp->mChildPerspective.GetUnit() == eStyleUnit_Coord &&
2566 0 : parentDisp->mChildPerspective.GetCoordValue() > 0.0) {
2567 0 : gfx3DMatrix perspective;
2568 : perspective._34 =
2569 : -1.0 / NSAppUnitsToFloatPixels(parentDisp->mChildPerspective.GetCoordValue(),
2570 0 : aAppUnitsPerPixel);
2571 : /* At the point when perspective is applied, we have been translated to the transform origin.
2572 : * The translation to the perspective origin is the difference between these values.
2573 : */
2574 0 : gfxPoint3D toPerspectiveOrigin = GetDeltaToMozPerspectiveOrigin(aFrame, aAppUnitsPerPixel);
2575 0 : result = result * nsLayoutUtils::ChangeMatrixBasis(toPerspectiveOrigin - toMozOrigin, perspective);
2576 : }
2577 :
2578 0 : if (aFrame->Preserves3D() && nsLayoutUtils::Are3DTransformsEnabled()) {
2579 : // Include the transform set on our parent
2580 0 : NS_ASSERTION(aFrame->GetParent() &&
2581 : aFrame->GetParent()->IsTransformed() &&
2582 : aFrame->GetParent()->Preserves3DChildren(),
2583 : "Preserve3D mismatch!");
2584 0 : gfx3DMatrix parent = GetResultingTransformMatrix(aFrame->GetParent(), aOrigin - aFrame->GetPosition(),
2585 0 : aAppUnitsPerPixel, nsnull, aOutAncestor);
2586 0 : return nsLayoutUtils::ChangeMatrixBasis(newOrigin + toMozOrigin, result) * parent;
2587 : }
2588 :
2589 : return nsLayoutUtils::ChangeMatrixBasis
2590 0 : (newOrigin + toMozOrigin, result);
2591 : }
2592 :
2593 : bool
2594 0 : nsDisplayTransform::ShouldPrerenderTransformedContent(nsDisplayListBuilder* aBuilder,
2595 : nsIFrame* aFrame)
2596 : {
2597 0 : if (aFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer)) {
2598 0 : nsSize refSize = aBuilder->ReferenceFrame()->GetSize();
2599 : // Only prerender if the transformed frame's size is <= the
2600 : // reference frame size (~viewport), allowing a 1/8th fuzz factor
2601 : // for shadows, borders, etc.
2602 0 : refSize += nsSize(refSize.width / 8, refSize.height / 8);
2603 0 : if (aFrame->GetVisualOverflowRectRelativeToSelf().Size() <= refSize) {
2604 : // Bug 717521 - pre-render max 4096 x 4096 device pixels.
2605 0 : nscoord max = aFrame->PresContext()->DevPixelsToAppUnits(4096);
2606 0 : nsRect visual = aFrame->GetVisualOverflowRect();
2607 0 : if (visual.width <= max && visual.height <= max) {
2608 0 : return true;
2609 : }
2610 : }
2611 : }
2612 0 : return false;
2613 : }
2614 :
2615 : /* If the matrix is singular, or a hidden backface is shown, the frame won't be visible or hit. */
2616 0 : static bool IsFrameVisible(nsIFrame* aFrame, const gfx3DMatrix& aMatrix)
2617 : {
2618 0 : if (aMatrix.IsSingular()) {
2619 0 : return false;
2620 : }
2621 0 : if (aFrame->GetStyleDisplay()->mBackfaceVisibility == NS_STYLE_BACKFACE_VISIBILITY_HIDDEN &&
2622 0 : aMatrix.IsBackfaceVisible()) {
2623 0 : return false;
2624 : }
2625 0 : return true;
2626 : }
2627 :
2628 : const gfx3DMatrix&
2629 0 : nsDisplayTransform::GetTransform(float aAppUnitsPerPixel)
2630 : {
2631 0 : if (mTransform.IsIdentity() || mCachedAppUnitsPerPixel != aAppUnitsPerPixel) {
2632 : mTransform =
2633 0 : GetResultingTransformMatrix(mFrame, ToReferenceFrame(),
2634 : aAppUnitsPerPixel,
2635 0 : nsnull);
2636 0 : mCachedAppUnitsPerPixel = aAppUnitsPerPixel;
2637 : }
2638 0 : return mTransform;
2639 : }
2640 :
2641 0 : already_AddRefed<Layer> nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBuilder,
2642 : LayerManager *aManager,
2643 : const ContainerParameters& aContainerParameters)
2644 : {
2645 : const gfx3DMatrix& newTransformMatrix =
2646 0 : GetTransform(mFrame->PresContext()->AppUnitsPerDevPixel());
2647 :
2648 0 : if (!IsFrameVisible(mFrame, newTransformMatrix)) {
2649 0 : return nsnull;
2650 : }
2651 :
2652 : nsRefPtr<ContainerLayer> container = aBuilder->LayerBuilder()->
2653 0 : BuildContainerLayerFor(aBuilder, aManager, mFrame, this, *mStoredList.GetList(),
2654 0 : aContainerParameters, &newTransformMatrix);
2655 :
2656 : // Add the preserve-3d flag for this layer, BuildContainerLayerFor clears all flags,
2657 : // so we never need to explicitely unset this flag.
2658 0 : if (mFrame->Preserves3D() || mFrame->Preserves3DChildren()) {
2659 0 : container->SetContentFlags(container->GetContentFlags() | Layer::CONTENT_PRESERVE_3D);
2660 : }
2661 0 : return container.forget();
2662 : }
2663 :
2664 : nsDisplayItem::LayerState
2665 0 : nsDisplayTransform::GetLayerState(nsDisplayListBuilder* aBuilder,
2666 : LayerManager* aManager) {
2667 : // Here we check if the *post-transform* bounds of this item are big enough
2668 : // to justify an active layer.
2669 0 : if (mFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer) &&
2670 0 : !IsItemTooSmallForActiveLayer(this))
2671 0 : return LAYER_ACTIVE;
2672 0 : if (!GetTransform(mFrame->PresContext()->AppUnitsPerDevPixel()).Is2D() || mFrame->Preserves3D())
2673 0 : return LAYER_ACTIVE;
2674 : nsIFrame* activeScrolledRoot =
2675 0 : nsLayoutUtils::GetActiveScrolledRootFor(mFrame, nsnull);
2676 : return !mStoredList.ChildrenCanBeInactive(aBuilder,
2677 : aManager,
2678 0 : *mStoredList.GetList(),
2679 0 : activeScrolledRoot)
2680 0 : ? LAYER_ACTIVE : LAYER_INACTIVE;
2681 : }
2682 :
2683 0 : bool nsDisplayTransform::ComputeVisibility(nsDisplayListBuilder *aBuilder,
2684 : nsRegion *aVisibleRegion,
2685 : const nsRect& aAllowVisibleRegionExpansion)
2686 : {
2687 : /* As we do this, we need to be sure to
2688 : * untransform the visible rect, since we want everything that's painting to
2689 : * think that it's painting in its original rectangular coordinate space.
2690 : * If we can't untransform, take the entire overflow rect */
2691 0 : nsRect untransformedVisibleRect;
2692 0 : float factor = nsPresContext::AppUnitsPerCSSPixel();
2693 0 : if (ShouldPrerenderTransformedContent(aBuilder, mFrame) ||
2694 : !UntransformRectMatrix(mVisibleRect,
2695 0 : GetTransform(factor),
2696 : factor,
2697 0 : &untransformedVisibleRect))
2698 : {
2699 0 : untransformedVisibleRect = mFrame->GetVisualOverflowRectRelativeToSelf() +
2700 0 : aBuilder->ToReferenceFrame(mFrame);
2701 : }
2702 0 : nsRegion untransformedVisible = untransformedVisibleRect;
2703 : // Call RecomputeVisiblity instead of ComputeVisibility since
2704 : // nsDisplayItem::ComputeVisibility should only be called from
2705 : // nsDisplayList::ComputeVisibility (which sets mVisibleRect on the item)
2706 0 : mStoredList.RecomputeVisibility(aBuilder, &untransformedVisible);
2707 0 : return true;
2708 : }
2709 :
2710 : #ifdef DEBUG_HIT
2711 : #include <time.h>
2712 : #endif
2713 :
2714 : /* HitTest does some fun stuff with matrix transforms to obtain the answer. */
2715 0 : void nsDisplayTransform::HitTest(nsDisplayListBuilder *aBuilder,
2716 : const nsRect& aRect,
2717 : HitTestState *aState,
2718 : nsTArray<nsIFrame*> *aOutFrames)
2719 : {
2720 : /* Here's how this works:
2721 : * 1. Get the matrix. If it's singular, abort (clearly we didn't hit
2722 : * anything).
2723 : * 2. Invert the matrix.
2724 : * 3. Use it to transform the rect into the correct space.
2725 : * 4. Pass that rect down through to the list's version of HitTest.
2726 : */
2727 0 : float factor = nsPresContext::AppUnitsPerCSSPixel();
2728 0 : gfx3DMatrix matrix = GetTransform(factor);
2729 :
2730 0 : if (!IsFrameVisible(mFrame, matrix)) {
2731 0 : return;
2732 : }
2733 :
2734 : /* We want to go from transformed-space to regular space.
2735 : * Thus we have to invert the matrix, which normally does
2736 : * the reverse operation (e.g. regular->transformed)
2737 : */
2738 :
2739 : /* Now, apply the transform and pass it down the channel. */
2740 0 : nsRect resultingRect;
2741 0 : if (aRect.width == 1 && aRect.height == 1) {
2742 : // Magic width/height indicating we're hit testing a point, not a rect
2743 : gfxPoint point = matrix.Inverse().ProjectPoint(
2744 0 : gfxPoint(NSAppUnitsToFloatPixels(aRect.x, factor),
2745 0 : NSAppUnitsToFloatPixels(aRect.y, factor)));
2746 :
2747 : resultingRect = nsRect(NSFloatPixelsToAppUnits(float(point.x), factor),
2748 : NSFloatPixelsToAppUnits(float(point.y), factor),
2749 0 : 1, 1);
2750 :
2751 : } else {
2752 0 : gfxRect originalRect(NSAppUnitsToFloatPixels(aRect.x, factor),
2753 0 : NSAppUnitsToFloatPixels(aRect.y, factor),
2754 0 : NSAppUnitsToFloatPixels(aRect.width, factor),
2755 0 : NSAppUnitsToFloatPixels(aRect.height, factor));
2756 :
2757 0 : gfxRect rect = matrix.Inverse().ProjectRectBounds(originalRect);;
2758 :
2759 0 : resultingRect = nsRect(NSFloatPixelsToAppUnits(float(rect.X()), factor),
2760 0 : NSFloatPixelsToAppUnits(float(rect.Y()), factor),
2761 0 : NSFloatPixelsToAppUnits(float(rect.Width()), factor),
2762 0 : NSFloatPixelsToAppUnits(float(rect.Height()), factor));
2763 : }
2764 :
2765 :
2766 : #ifdef DEBUG_HIT
2767 : printf("Frame: %p\n", dynamic_cast<void *>(mFrame));
2768 : printf(" Untransformed point: (%f, %f)\n", resultingRect.X(), resultingRect.Y());
2769 : PRUint32 originalFrameCount = aOutFrames.Length();
2770 : #endif
2771 :
2772 0 : mStoredList.HitTest(aBuilder, resultingRect, aState, aOutFrames);
2773 :
2774 : #ifdef DEBUG_HIT
2775 : if (originalFrameCount != aOutFrames.Length())
2776 : printf(" Hit! Time: %f, first frame: %p\n", static_cast<double>(clock()),
2777 : dynamic_cast<void *>(aOutFrames.ElementAt(0)));
2778 : printf("=== end of hit test ===\n");
2779 : #endif
2780 :
2781 : }
2782 :
2783 : float
2784 0 : nsDisplayTransform::GetHitDepthAtPoint(const nsPoint& aPoint)
2785 : {
2786 0 : float factor = nsPresContext::AppUnitsPerCSSPixel();
2787 0 : gfx3DMatrix matrix = GetTransform(factor);
2788 :
2789 0 : NS_ASSERTION(IsFrameVisible(mFrame, matrix), "We can't have hit a frame that isn't visible!");
2790 :
2791 : gfxPoint point =
2792 0 : matrix.Inverse().ProjectPoint(gfxPoint(NSAppUnitsToFloatPixels(aPoint.x, factor),
2793 0 : NSAppUnitsToFloatPixels(aPoint.y, factor)));
2794 :
2795 0 : gfxPoint3D transformed = matrix.Transform3D(gfxPoint3D(point.x, point.y, 0));
2796 0 : return transformed.z;
2797 : }
2798 :
2799 : /* The bounding rectangle for the object is the overflow rectangle translated
2800 : * by the reference point.
2801 : */
2802 0 : nsRect nsDisplayTransform::GetBounds(nsDisplayListBuilder *aBuilder)
2803 : {
2804 : nsRect untransformedBounds =
2805 0 : ShouldPrerenderTransformedContent(aBuilder, mFrame) ?
2806 0 : mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame() :
2807 0 : mStoredList.GetBounds(aBuilder);
2808 0 : float factor = nsPresContext::AppUnitsPerCSSPixel();
2809 : return nsLayoutUtils::MatrixTransformRect(untransformedBounds,
2810 0 : GetTransform(factor),
2811 0 : factor);
2812 : }
2813 :
2814 : /* The transform is opaque iff the transform consists solely of scales and
2815 : * translations and if the underlying content is opaque. Thus if the transform
2816 : * is of the form
2817 : *
2818 : * |a c e|
2819 : * |b d f|
2820 : * |0 0 1|
2821 : *
2822 : * We need b and c to be zero.
2823 : *
2824 : * We also need to check whether the underlying opaque content completely fills
2825 : * our visible rect. We use UntransformRect which expands to the axis-aligned
2826 : * bounding rect, but that's OK since if
2827 : * mStoredList.GetVisibleRect().Contains(untransformedVisible), then it
2828 : * certainly contains the actual (non-axis-aligned) untransformed rect.
2829 : */
2830 0 : nsRegion nsDisplayTransform::GetOpaqueRegion(nsDisplayListBuilder *aBuilder,
2831 : bool* aForceTransparentSurface)
2832 : {
2833 0 : if (aForceTransparentSurface) {
2834 0 : *aForceTransparentSurface = false;
2835 : }
2836 0 : nsRect untransformedVisible;
2837 0 : float factor = nsPresContext::AppUnitsPerCSSPixel();
2838 0 : if (!UntransformRectMatrix(mVisibleRect, GetTransform(factor), factor, &untransformedVisible)) {
2839 0 : return nsRegion();
2840 : }
2841 :
2842 0 : const gfx3DMatrix& matrix = GetTransform(nsPresContext::AppUnitsPerCSSPixel());
2843 :
2844 0 : nsRegion result;
2845 0 : gfxMatrix matrix2d;
2846 0 : if (matrix.Is2D(&matrix2d) &&
2847 0 : matrix2d.PreservesAxisAlignedRectangles() &&
2848 0 : mStoredList.GetOpaqueRegion(aBuilder).Contains(untransformedVisible)) {
2849 0 : result = mVisibleRect;
2850 : }
2851 0 : return result;
2852 : }
2853 :
2854 : /* The transform is uniform if it fills the entire bounding rect and the
2855 : * wrapped list is uniform. See GetOpaqueRegion for discussion of why this
2856 : * works.
2857 : */
2858 0 : bool nsDisplayTransform::IsUniform(nsDisplayListBuilder *aBuilder, nscolor* aColor)
2859 : {
2860 0 : nsRect untransformedVisible;
2861 0 : float factor = nsPresContext::AppUnitsPerCSSPixel();
2862 0 : if (!UntransformRectMatrix(mVisibleRect, GetTransform(factor), factor, &untransformedVisible)) {
2863 0 : return false;
2864 : }
2865 0 : const gfx3DMatrix& matrix = GetTransform(nsPresContext::AppUnitsPerCSSPixel());
2866 :
2867 0 : gfxMatrix matrix2d;
2868 0 : return matrix.Is2D(&matrix2d) &&
2869 0 : matrix2d.PreservesAxisAlignedRectangles() &&
2870 0 : mStoredList.GetVisibleRect().Contains(untransformedVisible) &&
2871 0 : mStoredList.IsUniform(aBuilder, aColor);
2872 : }
2873 :
2874 : /* If UNIFIED_CONTINUATIONS is defined, we can merge two display lists that
2875 : * share the same underlying content. Otherwise, doing so results in graphical
2876 : * glitches.
2877 : */
2878 : #ifndef UNIFIED_CONTINUATIONS
2879 :
2880 : bool
2881 0 : nsDisplayTransform::TryMerge(nsDisplayListBuilder *aBuilder,
2882 : nsDisplayItem *aItem)
2883 : {
2884 0 : return false;
2885 : }
2886 :
2887 : #else
2888 :
2889 : bool
2890 : nsDisplayTransform::TryMerge(nsDisplayListBuilder *aBuilder,
2891 : nsDisplayItem *aItem)
2892 : {
2893 : NS_PRECONDITION(aItem, "Why did you try merging with a null item?");
2894 : NS_PRECONDITION(aBuilder, "Why did you try merging with a null builder?");
2895 :
2896 : /* Make sure that we're dealing with two transforms. */
2897 : if (aItem->GetType() != TYPE_TRANSFORM)
2898 : return false;
2899 :
2900 : /* Check to see that both frames are part of the same content. */
2901 : if (aItem->GetUnderlyingFrame()->GetContent() != mFrame->GetContent())
2902 : return false;
2903 :
2904 : /* Now, move everything over to this frame and signal that
2905 : * we merged things!
2906 : */
2907 : mStoredList.GetList()->
2908 : AppendToBottom(&static_cast<nsDisplayTransform *>(aItem)->mStoredList);
2909 : return true;
2910 : }
2911 :
2912 : #endif
2913 :
2914 : /* TransformRect takes in as parameters a rectangle (in app space) and returns
2915 : * the smallest rectangle (in app space) containing the transformed image of
2916 : * that rectangle. That is, it takes the four corners of the rectangle,
2917 : * transforms them according to the matrix associated with the specified frame,
2918 : * then returns the smallest rectangle containing the four transformed points.
2919 : *
2920 : * @param aUntransformedBounds The rectangle (in app units) to transform.
2921 : * @param aFrame The frame whose transformation should be applied.
2922 : * @param aOrigin The delta from the frame origin to the coordinate space origin
2923 : * @param aBoundsOverride (optional) Force the frame bounds to be the
2924 : * specified bounds.
2925 : * @return The smallest rectangle containing the image of the transformed
2926 : * rectangle.
2927 : */
2928 0 : nsRect nsDisplayTransform::TransformRect(const nsRect &aUntransformedBounds,
2929 : const nsIFrame* aFrame,
2930 : const nsPoint &aOrigin,
2931 : const nsRect* aBoundsOverride)
2932 : {
2933 0 : NS_PRECONDITION(aFrame, "Can't take the transform based on a null frame!");
2934 :
2935 0 : float factor = nsPresContext::AppUnitsPerCSSPixel();
2936 : return nsLayoutUtils::MatrixTransformRect
2937 : (aUntransformedBounds,
2938 : GetResultingTransformMatrix(aFrame, aOrigin, factor, aBoundsOverride),
2939 0 : factor);
2940 : }
2941 :
2942 0 : nsRect nsDisplayTransform::TransformRectOut(const nsRect &aUntransformedBounds,
2943 : const nsIFrame* aFrame,
2944 : const nsPoint &aOrigin,
2945 : const nsRect* aBoundsOverride)
2946 : {
2947 0 : NS_PRECONDITION(aFrame, "Can't take the transform based on a null frame!");
2948 :
2949 0 : float factor = nsPresContext::AppUnitsPerCSSPixel();
2950 : return nsLayoutUtils::MatrixTransformRectOut
2951 : (aUntransformedBounds,
2952 : GetResultingTransformMatrix(aFrame, aOrigin, factor, aBoundsOverride),
2953 0 : factor);
2954 : }
2955 :
2956 0 : bool nsDisplayTransform::UntransformRectMatrix(const nsRect &aUntransformedBounds,
2957 : const gfx3DMatrix& aMatrix,
2958 : float aAppUnitsPerPixel,
2959 : nsRect *aOutRect)
2960 : {
2961 0 : if (aMatrix.IsSingular())
2962 0 : return false;
2963 :
2964 0 : gfxRect result(NSAppUnitsToFloatPixels(aUntransformedBounds.x, aAppUnitsPerPixel),
2965 0 : NSAppUnitsToFloatPixels(aUntransformedBounds.y, aAppUnitsPerPixel),
2966 0 : NSAppUnitsToFloatPixels(aUntransformedBounds.width, aAppUnitsPerPixel),
2967 0 : NSAppUnitsToFloatPixels(aUntransformedBounds.height, aAppUnitsPerPixel));
2968 :
2969 : /* We want to untransform the matrix, so invert the transformation first! */
2970 0 : result = aMatrix.Inverse().ProjectRectBounds(result);
2971 :
2972 0 : *aOutRect = nsLayoutUtils::RoundGfxRectToAppRect(result, aAppUnitsPerPixel);
2973 :
2974 0 : return true;
2975 : }
2976 :
2977 0 : bool nsDisplayTransform::UntransformRect(const nsRect &aUntransformedBounds,
2978 : const nsIFrame* aFrame,
2979 : const nsPoint &aOrigin,
2980 : nsRect* aOutRect)
2981 : {
2982 0 : NS_PRECONDITION(aFrame, "Can't take the transform based on a null frame!");
2983 :
2984 : /* Grab the matrix. If the transform is degenerate, just hand back the
2985 : * empty rect.
2986 : */
2987 0 : float factor = nsPresContext::AppUnitsPerCSSPixel();
2988 0 : gfx3DMatrix matrix = GetResultingTransformMatrix(aFrame, aOrigin, factor, nsnull);
2989 :
2990 0 : return UntransformRectMatrix(aUntransformedBounds, matrix, factor, aOutRect);
2991 : }
2992 :
2993 0 : nsDisplaySVGEffects::nsDisplaySVGEffects(nsDisplayListBuilder* aBuilder,
2994 : nsIFrame* aFrame, nsDisplayList* aList)
2995 : : nsDisplayWrapList(aBuilder, aFrame, aList), mEffectsFrame(aFrame),
2996 0 : mBounds(aFrame->GetVisualOverflowRectRelativeToSelf())
2997 : {
2998 0 : MOZ_COUNT_CTOR(nsDisplaySVGEffects);
2999 0 : }
3000 :
3001 : #ifdef NS_BUILD_REFCNT_LOGGING
3002 0 : nsDisplaySVGEffects::~nsDisplaySVGEffects()
3003 : {
3004 0 : MOZ_COUNT_DTOR(nsDisplaySVGEffects);
3005 0 : }
3006 : #endif
3007 :
3008 0 : nsRegion nsDisplaySVGEffects::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
3009 : bool* aForceTransparentSurface)
3010 : {
3011 0 : if (aForceTransparentSurface) {
3012 0 : *aForceTransparentSurface = false;
3013 : }
3014 0 : return nsRegion();
3015 : }
3016 :
3017 : void
3018 0 : nsDisplaySVGEffects::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
3019 : HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
3020 : {
3021 0 : nsPoint rectCenter(aRect.x + aRect.width / 2, aRect.y + aRect.height / 2);
3022 0 : if (nsSVGIntegrationUtils::HitTestFrameForEffects(mEffectsFrame,
3023 0 : rectCenter - aBuilder->ToReferenceFrame(mEffectsFrame))) {
3024 0 : mList.HitTest(aBuilder, aRect, aState, aOutFrames);
3025 : }
3026 0 : }
3027 :
3028 0 : void nsDisplaySVGEffects::Paint(nsDisplayListBuilder* aBuilder,
3029 : nsRenderingContext* aCtx)
3030 : {
3031 : nsSVGIntegrationUtils::PaintFramesWithEffects(aCtx,
3032 0 : mEffectsFrame, mVisibleRect, aBuilder, &mList);
3033 0 : }
3034 :
3035 0 : bool nsDisplaySVGEffects::ComputeVisibility(nsDisplayListBuilder* aBuilder,
3036 : nsRegion* aVisibleRegion,
3037 : const nsRect& aAllowVisibleRegionExpansion) {
3038 0 : nsPoint offset = aBuilder->ToReferenceFrame(mEffectsFrame);
3039 : nsRect dirtyRect =
3040 : nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(mEffectsFrame,
3041 0 : mVisibleRect - offset) +
3042 0 : offset;
3043 :
3044 : // Our children may be made translucent or arbitrarily deformed so we should
3045 : // not allow them to subtract area from aVisibleRegion.
3046 0 : nsRegion childrenVisible(dirtyRect);
3047 0 : nsRect r;
3048 0 : r.IntersectRect(dirtyRect, mList.GetBounds(aBuilder));
3049 0 : mList.ComputeVisibilityForSublist(aBuilder, &childrenVisible, r, nsRect());
3050 0 : return true;
3051 : }
3052 :
3053 0 : bool nsDisplaySVGEffects::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem)
3054 : {
3055 0 : if (aItem->GetType() != TYPE_SVG_EFFECTS)
3056 0 : return false;
3057 : // items for the same content element should be merged into a single
3058 : // compositing group
3059 : // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplaySVGEffects
3060 0 : if (aItem->GetUnderlyingFrame()->GetContent() != mFrame->GetContent())
3061 0 : return false;
3062 0 : nsDisplaySVGEffects* other = static_cast<nsDisplaySVGEffects*>(aItem);
3063 0 : mList.AppendToBottom(&other->mList);
3064 : mBounds.UnionRect(mBounds,
3065 0 : other->mBounds + other->mEffectsFrame->GetOffsetTo(mEffectsFrame));
3066 0 : return true;
3067 : }
3068 :
3069 : #ifdef MOZ_DUMP_PAINTING
3070 : void
3071 0 : nsDisplaySVGEffects::PrintEffects(FILE* aOutput)
3072 : {
3073 : nsIFrame* firstFrame =
3074 0 : nsLayoutUtils::GetFirstContinuationOrSpecialSibling(mEffectsFrame);
3075 : nsSVGEffects::EffectProperties effectProperties =
3076 0 : nsSVGEffects::GetEffectProperties(firstFrame);
3077 0 : bool isOK = true;
3078 0 : nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK);
3079 0 : bool first = true;
3080 0 : fprintf(aOutput, " effects=(");
3081 0 : if (mEffectsFrame->GetStyleDisplay()->mOpacity != 1.0f) {
3082 0 : first = false;
3083 0 : fprintf(aOutput, "opacity(%f)", mEffectsFrame->GetStyleDisplay()->mOpacity);
3084 : }
3085 0 : if (clipPathFrame) {
3086 0 : if (!first) {
3087 0 : fprintf(aOutput, ", ");
3088 : }
3089 0 : fprintf(aOutput, "clip(%s)", clipPathFrame->IsTrivial() ? "trivial" : "non-trivial");
3090 0 : first = false;
3091 : }
3092 0 : if (effectProperties.GetFilterFrame(&isOK)) {
3093 0 : if (!first) {
3094 0 : fprintf(aOutput, ", ");
3095 : }
3096 0 : fprintf(aOutput, "filter");
3097 0 : first = false;
3098 : }
3099 0 : if (effectProperties.GetMaskFrame(&isOK)) {
3100 0 : if (!first) {
3101 0 : fprintf(aOutput, ", ");
3102 : }
3103 0 : fprintf(aOutput, "mask");
3104 : }
3105 0 : fprintf(aOutput, ")");
3106 0 : }
3107 : #endif
3108 :
|