1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : //
39 : // Eric Vaughan
40 : // Netscape Communications
41 : //
42 : // See documentation in associated header file
43 : //
44 :
45 : #include "nsImageBoxFrame.h"
46 : #include "nsGkAtoms.h"
47 : #include "nsStyleContext.h"
48 : #include "nsStyleConsts.h"
49 : #include "nsCOMPtr.h"
50 : #include "nsPresContext.h"
51 : #include "nsBoxLayoutState.h"
52 :
53 : #include "nsHTMLParts.h"
54 : #include "nsString.h"
55 : #include "nsLeafFrame.h"
56 : #include "nsIPresShell.h"
57 : #include "nsIDocument.h"
58 : #include "nsIHTMLDocument.h"
59 : #include "nsImageMap.h"
60 : #include "nsILinkHandler.h"
61 : #include "nsIURL.h"
62 : #include "nsILoadGroup.h"
63 : #include "nsContainerFrame.h"
64 : #include "prprf.h"
65 : #include "nsCSSRendering.h"
66 : #include "nsIDOMHTMLImageElement.h"
67 : #include "nsINameSpaceManager.h"
68 : #include "nsTextFragment.h"
69 : #include "nsIDOMHTMLMapElement.h"
70 : #include "nsIDOMDocument.h"
71 : #include "nsTransform2D.h"
72 : #include "nsITheme.h"
73 : #include "nsIImageLoadingContent.h"
74 :
75 : #include "nsIServiceManager.h"
76 : #include "nsIURI.h"
77 : #include "nsNetUtil.h"
78 : #include "nsThreadUtils.h"
79 : #include "nsGUIEvent.h"
80 : #include "nsEventDispatcher.h"
81 : #include "nsDisplayList.h"
82 :
83 : #include "nsContentUtils.h"
84 :
85 : #define ONLOAD_CALLED_TOO_EARLY 1
86 :
87 : class nsImageBoxFrameEvent : public nsRunnable
88 0 : {
89 : public:
90 0 : nsImageBoxFrameEvent(nsIContent *content, PRUint32 message)
91 0 : : mContent(content), mMessage(message) {}
92 :
93 : NS_IMETHOD Run();
94 :
95 : private:
96 : nsCOMPtr<nsIContent> mContent;
97 : PRUint32 mMessage;
98 : };
99 :
100 : NS_IMETHODIMP
101 0 : nsImageBoxFrameEvent::Run()
102 : {
103 0 : nsIPresShell *pres_shell = mContent->OwnerDoc()->GetShell();
104 0 : if (!pres_shell) {
105 0 : return NS_OK;
106 : }
107 :
108 0 : nsRefPtr<nsPresContext> pres_context = pres_shell->GetPresContext();
109 0 : if (!pres_context) {
110 0 : return NS_OK;
111 : }
112 :
113 0 : nsEventStatus status = nsEventStatus_eIgnore;
114 0 : nsEvent event(true, mMessage);
115 :
116 0 : event.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
117 0 : nsEventDispatcher::Dispatch(mContent, pres_context, &event, nsnull, &status);
118 0 : return NS_OK;
119 : }
120 :
121 : // Fire off an event that'll asynchronously call the image elements
122 : // onload handler once handled. This is needed since the image library
123 : // can't decide if it wants to call it's observer methods
124 : // synchronously or asynchronously. If an image is loaded from the
125 : // cache the notifications come back synchronously, but if the image
126 : // is loaded from the netswork the notifications come back
127 : // asynchronously.
128 :
129 : void
130 0 : FireImageDOMEvent(nsIContent* aContent, PRUint32 aMessage)
131 : {
132 0 : NS_ASSERTION(aMessage == NS_LOAD || aMessage == NS_LOAD_ERROR,
133 : "invalid message");
134 :
135 0 : nsCOMPtr<nsIRunnable> event = new nsImageBoxFrameEvent(aContent, aMessage);
136 0 : if (NS_FAILED(NS_DispatchToCurrentThread(event)))
137 0 : NS_WARNING("failed to dispatch image event");
138 0 : }
139 :
140 : //
141 : // NS_NewImageBoxFrame
142 : //
143 : // Creates a new image frame and returns it
144 : //
145 : nsIFrame*
146 0 : NS_NewImageBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext)
147 : {
148 0 : return new (aPresShell) nsImageBoxFrame (aPresShell, aContext);
149 : }
150 :
151 0 : NS_IMPL_FRAMEARENA_HELPERS(nsImageBoxFrame)
152 :
153 : NS_IMETHODIMP
154 0 : nsImageBoxFrame::AttributeChanged(PRInt32 aNameSpaceID,
155 : nsIAtom* aAttribute,
156 : PRInt32 aModType)
157 : {
158 : nsresult rv = nsLeafBoxFrame::AttributeChanged(aNameSpaceID, aAttribute,
159 0 : aModType);
160 :
161 0 : if (aAttribute == nsGkAtoms::src) {
162 0 : UpdateImage();
163 0 : PresContext()->PresShell()->
164 0 : FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
165 : }
166 0 : else if (aAttribute == nsGkAtoms::validate)
167 0 : UpdateLoadFlags();
168 :
169 0 : return rv;
170 : }
171 :
172 0 : nsImageBoxFrame::nsImageBoxFrame(nsIPresShell* aShell, nsStyleContext* aContext):
173 : nsLeafBoxFrame(aShell, aContext),
174 : mIntrinsicSize(0,0),
175 : mRequestRegistered(false),
176 : mLoadFlags(nsIRequest::LOAD_NORMAL),
177 : mUseSrcAttr(false),
178 0 : mSuppressStyleCheck(false)
179 : {
180 0 : MarkIntrinsicWidthsDirty();
181 0 : }
182 :
183 0 : nsImageBoxFrame::~nsImageBoxFrame()
184 : {
185 0 : }
186 :
187 :
188 : /* virtual */ void
189 0 : nsImageBoxFrame::MarkIntrinsicWidthsDirty()
190 : {
191 0 : SizeNeedsRecalc(mImageSize);
192 0 : nsLeafBoxFrame::MarkIntrinsicWidthsDirty();
193 0 : }
194 :
195 : void
196 0 : nsImageBoxFrame::DestroyFrom(nsIFrame* aDestructRoot)
197 : {
198 0 : if (mImageRequest) {
199 : nsLayoutUtils::DeregisterImageRequest(PresContext(), mImageRequest,
200 0 : &mRequestRegistered);
201 :
202 : // Release image loader first so that it's refcnt can go to zero
203 0 : mImageRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
204 : }
205 :
206 0 : if (mListener)
207 0 : reinterpret_cast<nsImageBoxListener*>(mListener.get())->SetFrame(nsnull); // set the frame to null so we don't send messages to a dead object.
208 :
209 0 : nsLeafBoxFrame::DestroyFrom(aDestructRoot);
210 0 : }
211 :
212 :
213 : NS_IMETHODIMP
214 0 : nsImageBoxFrame::Init(nsIContent* aContent,
215 : nsIFrame* aParent,
216 : nsIFrame* aPrevInFlow)
217 : {
218 0 : if (!mListener) {
219 0 : nsImageBoxListener *listener = new nsImageBoxListener();
220 0 : NS_ADDREF(listener);
221 0 : listener->SetFrame(this);
222 0 : listener->QueryInterface(NS_GET_IID(imgIDecoderObserver), getter_AddRefs(mListener));
223 0 : NS_RELEASE(listener);
224 : }
225 :
226 0 : mSuppressStyleCheck = true;
227 0 : nsresult rv = nsLeafBoxFrame::Init(aContent, aParent, aPrevInFlow);
228 0 : mSuppressStyleCheck = false;
229 :
230 0 : UpdateLoadFlags();
231 0 : UpdateImage();
232 :
233 0 : return rv;
234 : }
235 :
236 : void
237 0 : nsImageBoxFrame::UpdateImage()
238 : {
239 0 : nsPresContext* presContext = PresContext();
240 :
241 0 : if (mImageRequest) {
242 : nsLayoutUtils::DeregisterImageRequest(presContext, mImageRequest,
243 0 : &mRequestRegistered);
244 0 : mImageRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
245 0 : mImageRequest = nsnull;
246 : }
247 :
248 : // get the new image src
249 0 : nsAutoString src;
250 0 : mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::src, src);
251 0 : mUseSrcAttr = !src.IsEmpty();
252 0 : if (mUseSrcAttr) {
253 0 : nsIDocument* doc = mContent->GetDocument();
254 0 : if (!doc) {
255 : // No need to do anything here...
256 : return;
257 : }
258 0 : nsCOMPtr<nsIURI> baseURI = mContent->GetBaseURI();
259 0 : nsCOMPtr<nsIURI> uri;
260 0 : nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri),
261 : src,
262 : doc,
263 0 : baseURI);
264 :
265 0 : if (uri && nsContentUtils::CanLoadImage(uri, mContent, doc,
266 0 : mContent->NodePrincipal())) {
267 : nsContentUtils::LoadImage(uri, doc, mContent->NodePrincipal(),
268 : doc->GetDocumentURI(), mListener, mLoadFlags,
269 0 : getter_AddRefs(mImageRequest));
270 :
271 0 : if (mImageRequest) {
272 : nsLayoutUtils::RegisterImageRequestIfAnimated(presContext,
273 : mImageRequest,
274 0 : &mRequestRegistered);
275 : }
276 : }
277 : } else {
278 : // Only get the list-style-image if we aren't being drawn
279 : // by a native theme.
280 0 : PRUint8 appearance = GetStyleDisplay()->mAppearance;
281 0 : if (!(appearance && nsBox::gTheme &&
282 0 : nsBox::gTheme->ThemeSupportsWidget(nsnull, this, appearance))) {
283 : // get the list-style-image
284 0 : imgIRequest *styleRequest = GetStyleList()->GetListStyleImage();
285 0 : if (styleRequest) {
286 0 : styleRequest->Clone(mListener, getter_AddRefs(mImageRequest));
287 : }
288 : }
289 : }
290 :
291 0 : if (!mImageRequest) {
292 : // We have no image, so size to 0
293 0 : mIntrinsicSize.SizeTo(0, 0);
294 : } else {
295 : // We don't want discarding or decode-on-draw for xul images.
296 0 : mImageRequest->RequestDecode();
297 0 : mImageRequest->LockImage();
298 : }
299 : }
300 :
301 : void
302 0 : nsImageBoxFrame::UpdateLoadFlags()
303 : {
304 : static nsIContent::AttrValuesArray strings[] =
305 : {&nsGkAtoms::always, &nsGkAtoms::never, nsnull};
306 0 : switch (mContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::validate,
307 0 : strings, eCaseMatters)) {
308 : case 0:
309 0 : mLoadFlags = nsIRequest::VALIDATE_ALWAYS;
310 0 : break;
311 : case 1:
312 0 : mLoadFlags = nsIRequest::VALIDATE_NEVER|nsIRequest::LOAD_FROM_CACHE;
313 0 : break;
314 : default:
315 0 : mLoadFlags = nsIRequest::LOAD_NORMAL;
316 0 : break;
317 : }
318 0 : }
319 :
320 : class nsDisplayXULImage : public nsDisplayItem {
321 : public:
322 0 : nsDisplayXULImage(nsDisplayListBuilder* aBuilder,
323 : nsImageBoxFrame* aFrame) :
324 0 : nsDisplayItem(aBuilder, aFrame) {
325 0 : MOZ_COUNT_CTOR(nsDisplayXULImage);
326 0 : }
327 : #ifdef NS_BUILD_REFCNT_LOGGING
328 0 : virtual ~nsDisplayXULImage() {
329 0 : MOZ_COUNT_DTOR(nsDisplayXULImage);
330 0 : }
331 : #endif
332 :
333 : // Doesn't handle HitTest because nsLeafBoxFrame already creates an
334 : // event receiver for us
335 : virtual void Paint(nsDisplayListBuilder* aBuilder,
336 : nsRenderingContext* aCtx);
337 0 : NS_DISPLAY_DECL_NAME("XULImage", TYPE_XUL_IMAGE)
338 : };
339 :
340 0 : void nsDisplayXULImage::Paint(nsDisplayListBuilder* aBuilder,
341 : nsRenderingContext* aCtx)
342 : {
343 : static_cast<nsImageBoxFrame*>(mFrame)->
344 0 : PaintImage(*aCtx, mVisibleRect, ToReferenceFrame(),
345 0 : aBuilder->ShouldSyncDecodeImages()
346 : ? (PRUint32) imgIContainer::FLAG_SYNC_DECODE
347 0 : : (PRUint32) imgIContainer::FLAG_NONE);
348 0 : }
349 :
350 : NS_IMETHODIMP
351 0 : nsImageBoxFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
352 : const nsRect& aDirtyRect,
353 : const nsDisplayListSet& aLists)
354 : {
355 0 : nsresult rv = nsLeafBoxFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
356 0 : NS_ENSURE_SUCCESS(rv, rv);
357 :
358 0 : if ((0 == mRect.width) || (0 == mRect.height)) {
359 : // Do not render when given a zero area. This avoids some useless
360 : // scaling work while we wait for our image dimensions to arrive
361 : // asynchronously.
362 0 : return NS_OK;
363 : }
364 :
365 0 : if (!IsVisibleForPainting(aBuilder))
366 0 : return NS_OK;
367 :
368 : return aLists.Content()->AppendNewToTop(
369 0 : new (aBuilder) nsDisplayXULImage(aBuilder, this));
370 : }
371 :
372 : void
373 0 : nsImageBoxFrame::PaintImage(nsRenderingContext& aRenderingContext,
374 : const nsRect& aDirtyRect, nsPoint aPt,
375 : PRUint32 aFlags)
376 : {
377 0 : nsRect rect;
378 0 : GetClientRect(rect);
379 :
380 0 : rect += aPt;
381 :
382 0 : if (!mImageRequest)
383 : return;
384 :
385 : // don't draw if the image is not dirty
386 0 : nsRect dirty;
387 0 : if (!dirty.IntersectRect(aDirtyRect, rect))
388 : return;
389 :
390 0 : nsCOMPtr<imgIContainer> imgCon;
391 0 : mImageRequest->GetImage(getter_AddRefs(imgCon));
392 :
393 0 : if (imgCon) {
394 0 : bool hasSubRect = !mUseSrcAttr && (mSubRect.width > 0 || mSubRect.height > 0);
395 : nsLayoutUtils::DrawSingleImage(&aRenderingContext, imgCon,
396 : nsLayoutUtils::GetGraphicsFilterForFrame(this),
397 0 : rect, dirty, aFlags, hasSubRect ? &mSubRect : nsnull);
398 : }
399 : }
400 :
401 :
402 : //
403 : // DidSetStyleContext
404 : //
405 : // When the style context changes, make sure that all of our image is up to date.
406 : //
407 : /* virtual */ void
408 0 : nsImageBoxFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
409 : {
410 0 : nsLeafBoxFrame::DidSetStyleContext(aOldStyleContext);
411 :
412 : // Fetch our subrect.
413 0 : const nsStyleList* myList = GetStyleList();
414 0 : mSubRect = myList->mImageRegion; // before |mSuppressStyleCheck| test!
415 :
416 0 : if (mUseSrcAttr || mSuppressStyleCheck)
417 0 : return; // No more work required, since the image isn't specified by style.
418 :
419 : // If we're using a native theme implementation, we shouldn't draw anything.
420 0 : const nsStyleDisplay* disp = GetStyleDisplay();
421 0 : if (disp->mAppearance && nsBox::gTheme &&
422 0 : nsBox::gTheme->ThemeSupportsWidget(nsnull, this, disp->mAppearance))
423 0 : return;
424 :
425 : // If list-style-image changes, we have a new image.
426 0 : nsCOMPtr<nsIURI> oldURI, newURI;
427 0 : if (mImageRequest)
428 0 : mImageRequest->GetURI(getter_AddRefs(oldURI));
429 0 : if (myList->GetListStyleImage())
430 0 : myList->GetListStyleImage()->GetURI(getter_AddRefs(newURI));
431 : bool equal;
432 0 : if (newURI == oldURI || // handles null==null
433 0 : (newURI && oldURI &&
434 0 : NS_SUCCEEDED(newURI->Equals(oldURI, &equal)) && equal))
435 : return;
436 :
437 0 : UpdateImage();
438 : } // DidSetStyleContext
439 :
440 : void
441 0 : nsImageBoxFrame::GetImageSize()
442 : {
443 0 : if (mIntrinsicSize.width > 0 && mIntrinsicSize.height > 0) {
444 0 : mImageSize.width = mIntrinsicSize.width;
445 0 : mImageSize.height = mIntrinsicSize.height;
446 : } else {
447 0 : mImageSize.width = 0;
448 0 : mImageSize.height = 0;
449 : }
450 0 : }
451 :
452 : /**
453 : * Ok return our dimensions
454 : */
455 : nsSize
456 0 : nsImageBoxFrame::GetPrefSize(nsBoxLayoutState& aState)
457 : {
458 0 : nsSize size(0,0);
459 0 : DISPLAY_PREF_SIZE(this, size);
460 0 : if (DoesNeedRecalc(mImageSize))
461 0 : GetImageSize();
462 :
463 0 : if (!mUseSrcAttr && (mSubRect.width > 0 || mSubRect.height > 0))
464 0 : size = nsSize(mSubRect.width, mSubRect.height);
465 : else
466 0 : size = mImageSize;
467 :
468 0 : nsSize intrinsicSize = size;
469 :
470 0 : nsMargin borderPadding(0,0,0,0);
471 0 : GetBorderAndPadding(borderPadding);
472 0 : size.width += borderPadding.LeftRight();
473 0 : size.height += borderPadding.TopBottom();
474 :
475 : bool widthSet, heightSet;
476 0 : nsIBox::AddCSSPrefSize(this, size, widthSet, heightSet);
477 0 : NS_ASSERTION(size.width != NS_INTRINSICSIZE && size.height != NS_INTRINSICSIZE,
478 : "non-intrinsic size expected");
479 :
480 0 : nsSize minSize = GetMinSize(aState);
481 0 : nsSize maxSize = GetMaxSize(aState);
482 :
483 0 : if (!widthSet && !heightSet) {
484 0 : if (minSize.width != NS_INTRINSICSIZE)
485 0 : minSize.width -= borderPadding.LeftRight();
486 0 : if (minSize.height != NS_INTRINSICSIZE)
487 0 : minSize.height -= borderPadding.TopBottom();
488 0 : if (maxSize.width != NS_INTRINSICSIZE)
489 0 : maxSize.width -= borderPadding.LeftRight();
490 0 : if (maxSize.height != NS_INTRINSICSIZE)
491 0 : maxSize.height -= borderPadding.TopBottom();
492 :
493 : size = nsLayoutUtils::ComputeAutoSizeWithIntrinsicDimensions(minSize.width, minSize.height,
494 : maxSize.width, maxSize.height,
495 0 : intrinsicSize.width, intrinsicSize.height);
496 0 : NS_ASSERTION(size.width != NS_INTRINSICSIZE && size.height != NS_INTRINSICSIZE,
497 : "non-intrinsic size expected");
498 0 : size.width += borderPadding.LeftRight();
499 0 : size.height += borderPadding.TopBottom();
500 0 : return size;
501 : }
502 :
503 0 : if (!widthSet) {
504 0 : if (intrinsicSize.height > 0) {
505 : // Subtract off the border and padding from the height because the
506 : // content-box needs to be used to determine the ratio
507 0 : nscoord height = size.height - borderPadding.TopBottom();
508 : size.width = nscoord(PRInt64(height) * PRInt64(intrinsicSize.width) /
509 0 : PRInt64(intrinsicSize.height));
510 : }
511 : else {
512 0 : size.width = intrinsicSize.width;
513 : }
514 :
515 0 : size.width += borderPadding.LeftRight();
516 : }
517 0 : else if (!heightSet) {
518 0 : if (intrinsicSize.width > 0) {
519 0 : nscoord width = size.width - borderPadding.LeftRight();
520 : size.height = nscoord(PRInt64(width) * PRInt64(intrinsicSize.height) /
521 0 : PRInt64(intrinsicSize.width));
522 : }
523 : else {
524 0 : size.height = intrinsicSize.height;
525 : }
526 :
527 0 : size.height += borderPadding.TopBottom();
528 : }
529 :
530 0 : return BoundsCheck(minSize, size, maxSize);
531 : }
532 :
533 : nsSize
534 0 : nsImageBoxFrame::GetMinSize(nsBoxLayoutState& aState)
535 : {
536 : // An image can always scale down to (0,0).
537 0 : nsSize size(0,0);
538 0 : DISPLAY_MIN_SIZE(this, size);
539 0 : AddBorderAndPadding(size);
540 : bool widthSet, heightSet;
541 0 : nsIBox::AddCSSMinSize(aState, this, size, widthSet, heightSet);
542 : return size;
543 : }
544 :
545 : nscoord
546 0 : nsImageBoxFrame::GetBoxAscent(nsBoxLayoutState& aState)
547 : {
548 0 : return GetPrefSize(aState).height;
549 : }
550 :
551 : nsIAtom*
552 0 : nsImageBoxFrame::GetType() const
553 : {
554 0 : return nsGkAtoms::imageBoxFrame;
555 : }
556 :
557 : #ifdef DEBUG
558 : NS_IMETHODIMP
559 0 : nsImageBoxFrame::GetFrameName(nsAString& aResult) const
560 : {
561 0 : return MakeFrameName(NS_LITERAL_STRING("ImageBox"), aResult);
562 : }
563 : #endif
564 :
565 :
566 0 : NS_IMETHODIMP nsImageBoxFrame::OnStartContainer(imgIRequest *request,
567 : imgIContainer *image)
568 : {
569 0 : NS_ENSURE_ARG_POINTER(image);
570 :
571 : // Ensure the animation (if any) is started. Note: There is no
572 : // corresponding call to Decrement for this. This Increment will be
573 : // 'cleaned up' by the Request when it is destroyed, but only then.
574 0 : request->IncrementAnimationConsumers();
575 :
576 : nscoord w, h;
577 0 : image->GetWidth(&w);
578 0 : image->GetHeight(&h);
579 :
580 : mIntrinsicSize.SizeTo(nsPresContext::CSSPixelsToAppUnits(w),
581 0 : nsPresContext::CSSPixelsToAppUnits(h));
582 :
583 0 : if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
584 0 : PresContext()->PresShell()->
585 0 : FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
586 : }
587 :
588 0 : return NS_OK;
589 : }
590 :
591 0 : NS_IMETHODIMP nsImageBoxFrame::OnStopContainer(imgIRequest *request,
592 : imgIContainer *image)
593 : {
594 0 : nsBoxLayoutState state(PresContext());
595 0 : this->Redraw(state);
596 :
597 0 : return NS_OK;
598 : }
599 :
600 0 : NS_IMETHODIMP nsImageBoxFrame::OnStopDecode(imgIRequest *request,
601 : nsresult aStatus,
602 : const PRUnichar *statusArg)
603 : {
604 0 : if (NS_SUCCEEDED(aStatus))
605 : // Fire an onload DOM event.
606 0 : FireImageDOMEvent(mContent, NS_LOAD);
607 : else {
608 : // Fire an onerror DOM event.
609 0 : mIntrinsicSize.SizeTo(0, 0);
610 0 : PresContext()->PresShell()->
611 0 : FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
612 0 : FireImageDOMEvent(mContent, NS_LOAD_ERROR);
613 : }
614 :
615 0 : return NS_OK;
616 : }
617 :
618 0 : NS_IMETHODIMP nsImageBoxFrame::OnImageIsAnimated(imgIRequest *aRequest)
619 : {
620 : // Register with our refresh driver, if we're animated.
621 : nsLayoutUtils::RegisterImageRequest(PresContext(), aRequest,
622 0 : &mRequestRegistered);
623 :
624 0 : return NS_OK;
625 : }
626 :
627 0 : NS_IMETHODIMP nsImageBoxFrame::FrameChanged(imgIRequest *aRequest,
628 : imgIContainer *aContainer,
629 : const nsIntRect *aDirtyRect)
630 : {
631 0 : nsBoxLayoutState state(PresContext());
632 0 : this->Redraw(state);
633 :
634 0 : return NS_OK;
635 : }
636 :
637 0 : NS_IMPL_ISUPPORTS2(nsImageBoxListener, imgIDecoderObserver, imgIContainerObserver)
638 :
639 0 : nsImageBoxListener::nsImageBoxListener()
640 : {
641 0 : }
642 :
643 0 : nsImageBoxListener::~nsImageBoxListener()
644 : {
645 0 : }
646 :
647 0 : NS_IMETHODIMP nsImageBoxListener::OnStartContainer(imgIRequest *request,
648 : imgIContainer *image)
649 : {
650 0 : if (!mFrame)
651 0 : return NS_OK;
652 :
653 0 : return mFrame->OnStartContainer(request, image);
654 : }
655 :
656 0 : NS_IMETHODIMP nsImageBoxListener::OnStopContainer(imgIRequest *request,
657 : imgIContainer *image)
658 : {
659 0 : if (!mFrame)
660 0 : return NS_OK;
661 :
662 0 : return mFrame->OnStopContainer(request, image);
663 : }
664 :
665 0 : NS_IMETHODIMP nsImageBoxListener::OnStopDecode(imgIRequest *request,
666 : nsresult status,
667 : const PRUnichar *statusArg)
668 : {
669 0 : if (!mFrame)
670 0 : return NS_OK;
671 :
672 0 : return mFrame->OnStopDecode(request, status, statusArg);
673 : }
674 :
675 0 : NS_IMETHODIMP nsImageBoxListener::OnImageIsAnimated(imgIRequest* aRequest)
676 : {
677 0 : if (!mFrame)
678 0 : return NS_OK;
679 :
680 0 : return mFrame->OnImageIsAnimated(aRequest);
681 : }
682 :
683 0 : NS_IMETHODIMP nsImageBoxListener::FrameChanged(imgIRequest *aRequest,
684 : imgIContainer *aContainer,
685 : const nsIntRect *aDirtyRect)
686 : {
687 0 : if (!mFrame)
688 0 : return NS_ERROR_FAILURE;
689 :
690 0 : return mFrame->FrameChanged(aRequest, aContainer, aDirtyRect);
691 : }
692 :
|