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.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * the Mozilla Foundation.
19 : * Portions created by the Initial Developer are Copyright (C) 2010
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Daniel Holbert <dholbert@mozilla.com>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * 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 : #include "VectorImage.h"
40 :
41 : #include "imgIDecoderObserver.h"
42 : #include "SVGDocumentWrapper.h"
43 : #include "gfxContext.h"
44 : #include "gfxPlatform.h"
45 : #include "nsPresContext.h"
46 : #include "nsRect.h"
47 : #include "nsIObserverService.h"
48 : #include "nsIPresShell.h"
49 : #include "nsIStreamListener.h"
50 : #include "nsComponentManagerUtils.h"
51 : #include "nsServiceManagerUtils.h"
52 : #include "nsSVGUtils.h" // for nsSVGUtils::ConvertToSurfaceSize
53 : #include "nsSVGEffects.h" // for nsSVGRenderingObserver
54 : #include "gfxDrawable.h"
55 : #include "gfxUtils.h"
56 : #include "nsSVGSVGElement.h"
57 :
58 : namespace mozilla {
59 :
60 : using namespace dom;
61 :
62 : namespace image {
63 :
64 : // Helper-class: SVGRootRenderingObserver
65 : class SVGRootRenderingObserver : public nsSVGRenderingObserver {
66 : public:
67 0 : SVGRootRenderingObserver(SVGDocumentWrapper* aDocWrapper,
68 : VectorImage* aVectorImage)
69 : : nsSVGRenderingObserver(),
70 : mDocWrapper(aDocWrapper),
71 0 : mVectorImage(aVectorImage)
72 : {
73 0 : StartListening();
74 0 : Element* elem = GetTarget();
75 0 : if (elem) {
76 0 : nsSVGEffects::AddRenderingObserver(elem, this);
77 0 : mInObserverList = true;
78 : }
79 : #ifdef DEBUG
80 : else {
81 0 : NS_ABORT_IF_FALSE(!mInObserverList,
82 : "Have no target, so we can't be in "
83 : "target's observer list...");
84 : }
85 : #endif
86 0 : }
87 :
88 0 : virtual ~SVGRootRenderingObserver()
89 0 : {
90 0 : StopListening();
91 0 : }
92 :
93 : protected:
94 0 : virtual Element* GetTarget()
95 : {
96 0 : return mDocWrapper->GetRootSVGElem();
97 : }
98 :
99 0 : virtual void DoUpdate()
100 : {
101 0 : Element* elem = GetTarget();
102 0 : if (!elem)
103 0 : return;
104 :
105 0 : if (!mDocWrapper->ShouldIgnoreInvalidation()) {
106 0 : nsIFrame* frame = elem->GetPrimaryFrame();
107 0 : if (!frame || frame->PresContext()->PresShell()->IsDestroying()) {
108 : // We're being destroyed. Bail out.
109 0 : return;
110 : }
111 :
112 0 : mVectorImage->InvalidateObserver();
113 : }
114 :
115 : // Our caller might've removed us from rendering-observer list.
116 : // Add ourselves back!
117 0 : if (!mInObserverList) {
118 0 : nsSVGEffects::AddRenderingObserver(elem, this);
119 0 : mInObserverList = true;
120 : }
121 : }
122 :
123 : // Private data
124 : nsRefPtr<SVGDocumentWrapper> mDocWrapper;
125 : VectorImage* mVectorImage; // Raw pointer because it owns me.
126 : };
127 :
128 : // Helper-class: SVGDrawingCallback
129 0 : class SVGDrawingCallback : public gfxDrawingCallback {
130 : public:
131 0 : SVGDrawingCallback(SVGDocumentWrapper* aSVGDocumentWrapper,
132 : const nsIntRect& aViewport,
133 : PRUint32 aImageFlags) :
134 : mSVGDocumentWrapper(aSVGDocumentWrapper),
135 : mViewport(aViewport),
136 0 : mImageFlags(aImageFlags)
137 0 : {}
138 : virtual bool operator()(gfxContext* aContext,
139 : const gfxRect& aFillRect,
140 : const gfxPattern::GraphicsFilter& aFilter,
141 : const gfxMatrix& aTransform);
142 : private:
143 : nsRefPtr<SVGDocumentWrapper> mSVGDocumentWrapper;
144 : const nsIntRect mViewport;
145 : PRUint32 mImageFlags;
146 : };
147 :
148 : // Based loosely on nsSVGIntegrationUtils' PaintFrameCallback::operator()
149 : bool
150 0 : SVGDrawingCallback::operator()(gfxContext* aContext,
151 : const gfxRect& aFillRect,
152 : const gfxPattern::GraphicsFilter& aFilter,
153 : const gfxMatrix& aTransform)
154 : {
155 0 : NS_ABORT_IF_FALSE(mSVGDocumentWrapper, "need an SVGDocumentWrapper");
156 :
157 : // Get (& sanity-check) the helper-doc's presShell
158 0 : nsCOMPtr<nsIPresShell> presShell;
159 0 : if (NS_FAILED(mSVGDocumentWrapper->GetPresShell(getter_AddRefs(presShell)))) {
160 0 : NS_WARNING("Unable to draw -- presShell lookup failed");
161 0 : return false;
162 : }
163 0 : NS_ABORT_IF_FALSE(presShell, "GetPresShell succeeded but returned null");
164 :
165 0 : gfxContextAutoSaveRestore contextRestorer(aContext);
166 :
167 : // Clip to aFillRect so that we don't paint outside.
168 0 : aContext->NewPath();
169 0 : aContext->Rectangle(aFillRect);
170 0 : aContext->Clip();
171 :
172 0 : gfxContextMatrixAutoSaveRestore contextMatrixRestorer(aContext);
173 0 : aContext->Multiply(gfxMatrix(aTransform).Invert());
174 :
175 0 : nsPresContext* presContext = presShell->GetPresContext();
176 0 : NS_ABORT_IF_FALSE(presContext, "pres shell w/out pres context");
177 :
178 : nsRect svgRect(presContext->DevPixelsToAppUnits(mViewport.x),
179 : presContext->DevPixelsToAppUnits(mViewport.y),
180 : presContext->DevPixelsToAppUnits(mViewport.width),
181 0 : presContext->DevPixelsToAppUnits(mViewport.height));
182 :
183 0 : PRUint32 renderDocFlags = nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING;
184 0 : if (!(mImageFlags & imgIContainer::FLAG_SYNC_DECODE)) {
185 0 : renderDocFlags |= nsIPresShell::RENDER_ASYNC_DECODE_IMAGES;
186 : }
187 :
188 0 : presShell->RenderDocument(svgRect, renderDocFlags,
189 : NS_RGBA(0, 0, 0, 0), // transparent
190 0 : aContext);
191 :
192 0 : return true;
193 : }
194 :
195 : // Implement VectorImage's nsISupports-inherited methods
196 0 : NS_IMPL_ISUPPORTS3(VectorImage,
197 : imgIContainer,
198 : nsIStreamListener,
199 : nsIRequestObserver)
200 :
201 : //------------------------------------------------------------------------------
202 : // Constructor / Destructor
203 :
204 0 : VectorImage::VectorImage(imgStatusTracker* aStatusTracker) :
205 : Image(aStatusTracker), // invoke superclass's constructor
206 : mRestrictedRegion(0, 0, 0, 0),
207 : mLastRenderedSize(0, 0),
208 : mIsInitialized(false),
209 : mIsFullyLoaded(false),
210 : mIsDrawing(false),
211 : mHaveAnimations(false),
212 0 : mHaveRestrictedRegion(false)
213 : {
214 0 : }
215 :
216 0 : VectorImage::~VectorImage()
217 : {
218 0 : }
219 :
220 : //------------------------------------------------------------------------------
221 : // Methods inherited from Image.h
222 :
223 : nsresult
224 0 : VectorImage::Init(imgIDecoderObserver* aObserver,
225 : const char* aMimeType,
226 : const char* aURIString,
227 : PRUint32 aFlags)
228 : {
229 : // We don't support re-initialization
230 0 : if (mIsInitialized)
231 0 : return NS_ERROR_ILLEGAL_VALUE;
232 :
233 0 : NS_ABORT_IF_FALSE(!mIsFullyLoaded && !mHaveAnimations &&
234 : !mHaveRestrictedRegion && !mError,
235 : "Flags unexpectedly set before initialization");
236 :
237 0 : mObserver = do_GetWeakReference(aObserver);
238 0 : NS_ABORT_IF_FALSE(!strcmp(aMimeType, SVG_MIMETYPE), "Unexpected mimetype");
239 :
240 0 : mIsInitialized = true;
241 :
242 0 : return NS_OK;
243 : }
244 :
245 : void
246 0 : VectorImage::GetCurrentFrameRect(nsIntRect& aRect)
247 : {
248 0 : aRect = nsIntRect::GetMaxSizedIntRect();
249 0 : }
250 :
251 : size_t
252 0 : VectorImage::HeapSizeOfSourceWithComputedFallback(nsMallocSizeOfFun aMallocSizeOf) const
253 : {
254 : // We're not storing the source data -- we just feed that directly to
255 : // our helper SVG document as we receive it, for it to parse.
256 : // So 0 is an appropriate return value here.
257 0 : return 0;
258 : }
259 :
260 : size_t
261 0 : VectorImage::HeapSizeOfDecodedWithComputedFallback(nsMallocSizeOfFun aMallocSizeOf) const
262 : {
263 : // XXXdholbert TODO: return num bytes used by helper SVG doc. (bug 590790)
264 0 : return 0;
265 : }
266 :
267 : size_t
268 0 : VectorImage::NonHeapSizeOfDecoded() const
269 : {
270 0 : return 0;
271 : }
272 :
273 : size_t
274 0 : VectorImage::OutOfProcessSizeOfDecoded() const
275 : {
276 0 : return 0;
277 : }
278 :
279 : nsresult
280 0 : VectorImage::StartAnimation()
281 : {
282 0 : if (mError)
283 0 : return NS_ERROR_FAILURE;
284 :
285 0 : NS_ABORT_IF_FALSE(ShouldAnimate(), "Should not animate!");
286 :
287 0 : mSVGDocumentWrapper->StartAnimation();
288 0 : return NS_OK;
289 : }
290 :
291 : nsresult
292 0 : VectorImage::StopAnimation()
293 : {
294 0 : if (mError)
295 0 : return NS_ERROR_FAILURE;
296 :
297 0 : NS_ABORT_IF_FALSE(mIsFullyLoaded && mHaveAnimations,
298 : "Should not have been animating!");
299 :
300 0 : mSVGDocumentWrapper->StopAnimation();
301 0 : return NS_OK;
302 : }
303 :
304 : bool
305 0 : VectorImage::ShouldAnimate()
306 : {
307 0 : return Image::ShouldAnimate() && mIsFullyLoaded && mHaveAnimations;
308 : }
309 :
310 : //------------------------------------------------------------------------------
311 : // imgIContainer methods
312 :
313 : //******************************************************************************
314 : /* readonly attribute PRInt32 width; */
315 : NS_IMETHODIMP
316 0 : VectorImage::GetWidth(PRInt32* aWidth)
317 : {
318 0 : if (mError || !mIsFullyLoaded) {
319 0 : *aWidth = 0;
320 0 : return NS_ERROR_FAILURE;
321 : }
322 :
323 0 : if (!mSVGDocumentWrapper->GetWidthOrHeight(SVGDocumentWrapper::eWidth,
324 0 : *aWidth)) {
325 0 : *aWidth = 0;
326 0 : return NS_ERROR_FAILURE;
327 : }
328 :
329 0 : return NS_OK;
330 : }
331 :
332 : //******************************************************************************
333 : /* [notxpcom] void requestRefresh ([const] in TimeStamp aTime); */
334 : NS_IMETHODIMP_(void)
335 0 : VectorImage::RequestRefresh(const mozilla::TimeStamp& aTime)
336 : {
337 : // TODO: Implement for b666446.
338 0 : }
339 :
340 : //******************************************************************************
341 : /* readonly attribute PRInt32 height; */
342 : NS_IMETHODIMP
343 0 : VectorImage::GetHeight(PRInt32* aHeight)
344 : {
345 0 : if (mError || !mIsFullyLoaded) {
346 0 : *aHeight = 0;
347 0 : return NS_ERROR_FAILURE;
348 : }
349 :
350 0 : if (!mSVGDocumentWrapper->GetWidthOrHeight(SVGDocumentWrapper::eHeight,
351 0 : *aHeight)) {
352 0 : *aHeight = 0;
353 0 : return NS_ERROR_FAILURE;
354 : }
355 :
356 0 : return NS_OK;
357 : }
358 :
359 : //******************************************************************************
360 : /* readonly attribute unsigned short type; */
361 : NS_IMETHODIMP
362 0 : VectorImage::GetType(PRUint16* aType)
363 : {
364 0 : NS_ENSURE_ARG_POINTER(aType);
365 :
366 0 : *aType = GetType();
367 0 : return NS_OK;
368 : }
369 :
370 : //******************************************************************************
371 : /* [noscript, notxpcom] PRUint16 GetType(); */
372 : NS_IMETHODIMP_(PRUint16)
373 0 : VectorImage::GetType()
374 : {
375 0 : return imgIContainer::TYPE_VECTOR;
376 : }
377 :
378 : //******************************************************************************
379 : /* readonly attribute boolean animated; */
380 : NS_IMETHODIMP
381 0 : VectorImage::GetAnimated(bool* aAnimated)
382 : {
383 0 : if (mError || !mIsFullyLoaded)
384 0 : return NS_ERROR_FAILURE;
385 :
386 0 : *aAnimated = mSVGDocumentWrapper->IsAnimated();
387 0 : return NS_OK;
388 : }
389 :
390 : //******************************************************************************
391 : /* readonly attribute boolean currentFrameIsOpaque; */
392 : NS_IMETHODIMP
393 0 : VectorImage::GetCurrentFrameIsOpaque(bool* aIsOpaque)
394 : {
395 0 : NS_ENSURE_ARG_POINTER(aIsOpaque);
396 0 : *aIsOpaque = false; // In general, SVG content is not opaque.
397 0 : return NS_OK;
398 : }
399 :
400 : //******************************************************************************
401 : /* [noscript] gfxASurface getFrame(in PRUint32 aWhichFrame,
402 : * in PRUint32 aFlags; */
403 : NS_IMETHODIMP
404 0 : VectorImage::GetFrame(PRUint32 aWhichFrame,
405 : PRUint32 aFlags,
406 : gfxASurface** _retval)
407 : {
408 0 : NS_ENSURE_ARG_POINTER(_retval);
409 0 : nsRefPtr<gfxImageSurface> surface;
410 0 : nsresult rv = CopyFrame(aWhichFrame, aFlags, getter_AddRefs(surface));
411 0 : if (NS_SUCCEEDED(rv)) {
412 0 : *_retval = surface.forget().get();
413 : }
414 0 : return rv;
415 : }
416 :
417 : //******************************************************************************
418 : /* [noscript] gfxImageSurface copyFrame(in PRUint32 aWhichFrame,
419 : * in PRUint32 aFlags); */
420 : NS_IMETHODIMP
421 0 : VectorImage::CopyFrame(PRUint32 aWhichFrame,
422 : PRUint32 aFlags,
423 : gfxImageSurface** _retval)
424 : {
425 0 : NS_ENSURE_ARG_POINTER(_retval);
426 : // XXXdholbert NOTE: Currently assuming FRAME_CURRENT for simplicity.
427 : // Could handle FRAME_FIRST by saving helper-doc current time, seeking
428 : // to time 0, rendering, and then seeking to saved time.
429 0 : if (aWhichFrame > FRAME_MAX_VALUE)
430 0 : return NS_ERROR_INVALID_ARG;
431 :
432 0 : if (mError)
433 0 : return NS_ERROR_FAILURE;
434 :
435 : // Look up height & width
436 : // ----------------------
437 0 : nsIntSize imageIntSize;
438 0 : if (!mSVGDocumentWrapper->GetWidthOrHeight(SVGDocumentWrapper::eWidth,
439 0 : imageIntSize.width) ||
440 : !mSVGDocumentWrapper->GetWidthOrHeight(SVGDocumentWrapper::eHeight,
441 0 : imageIntSize.height)) {
442 : // We'll get here if our SVG doc has a percent-valued width or height.
443 0 : return NS_ERROR_FAILURE;
444 : }
445 :
446 : // Create a surface that we'll ultimately return
447 : // ---------------------------------------------
448 : // Make our surface the size of what will ultimately be drawn to it.
449 : // (either the full image size, or the restricted region)
450 0 : gfxIntSize surfaceSize;
451 0 : if (mHaveRestrictedRegion) {
452 0 : surfaceSize.width = mRestrictedRegion.width;
453 0 : surfaceSize.height = mRestrictedRegion.height;
454 : } else {
455 0 : surfaceSize.width = imageIntSize.width;
456 0 : surfaceSize.height = imageIntSize.height;
457 : }
458 :
459 : nsRefPtr<gfxImageSurface> surface =
460 0 : new gfxImageSurface(surfaceSize, gfxASurface::ImageFormatARGB32);
461 0 : nsRefPtr<gfxContext> context = new gfxContext(surface);
462 :
463 : // Draw to our surface!
464 : // --------------------
465 : nsresult rv = Draw(context, gfxPattern::FILTER_NEAREST, gfxMatrix(),
466 : gfxRect(gfxPoint(0,0), gfxIntSize(imageIntSize.width,
467 : imageIntSize.height)),
468 : nsIntRect(nsIntPoint(0,0), imageIntSize),
469 0 : imageIntSize, aFlags);
470 0 : if (NS_SUCCEEDED(rv)) {
471 0 : *_retval = surface.forget().get();
472 : }
473 :
474 0 : return rv;
475 : }
476 :
477 : //******************************************************************************
478 : /* [noscript] imgIContainer extractFrame(PRUint32 aWhichFrame,
479 : * [const] in nsIntRect aRegion,
480 : * in PRUint32 aFlags); */
481 : NS_IMETHODIMP
482 0 : VectorImage::ExtractFrame(PRUint32 aWhichFrame,
483 : const nsIntRect& aRegion,
484 : PRUint32 aFlags,
485 : imgIContainer** _retval)
486 : {
487 0 : NS_ENSURE_ARG_POINTER(_retval);
488 0 : if (mError || !mIsFullyLoaded)
489 0 : return NS_ERROR_FAILURE;
490 :
491 : // XXXdholbert NOTE: This method assumes FRAME_CURRENT (not FRAME_FIRST)
492 : // right now, because mozilla doesn't actually contain any clients of this
493 : // method that use FRAME_FIRST. If it's needed, we *could* handle
494 : // FRAME_FIRST by saving the helper-doc's current SMIL time, seeking it to
495 : // time 0, rendering to a RasterImage, and then restoring our saved time.
496 0 : if (aWhichFrame != FRAME_CURRENT) {
497 : NS_WARNING("VectorImage::ExtractFrame with something other than "
498 0 : "FRAME_CURRENT isn't supported yet. Assuming FRAME_CURRENT.");
499 : }
500 :
501 : // XXXdholbert This method also doesn't actually freeze animation in the
502 : // returned imgIContainer, because it shares our helper-document. To
503 : // get a true snapshot, we need to clone the document - see bug 590792.
504 :
505 : // Make a new container with same SVG document.
506 0 : nsRefPtr<VectorImage> extractedImg = new VectorImage();
507 0 : extractedImg->mSVGDocumentWrapper = mSVGDocumentWrapper;
508 0 : extractedImg->mAnimationMode = kDontAnimMode;
509 :
510 0 : extractedImg->mRestrictedRegion.x = aRegion.x;
511 0 : extractedImg->mRestrictedRegion.y = aRegion.y;
512 :
513 : // (disallow negative width/height on our restricted region)
514 0 : extractedImg->mRestrictedRegion.width = NS_MAX(aRegion.width, 0);
515 0 : extractedImg->mRestrictedRegion.height = NS_MAX(aRegion.height, 0);
516 :
517 0 : extractedImg->mIsInitialized = true;
518 0 : extractedImg->mIsFullyLoaded = true;
519 0 : extractedImg->mHaveRestrictedRegion = true;
520 :
521 0 : *_retval = extractedImg.forget().get();
522 0 : return NS_OK;
523 : }
524 :
525 :
526 : //******************************************************************************
527 : /* [noscript] void draw(in gfxContext aContext,
528 : * in gfxGraphicsFilter aFilter,
529 : * [const] in gfxMatrix aUserSpaceToImageSpace,
530 : * [const] in gfxRect aFill,
531 : * [const] in nsIntRect aSubimage,
532 : * [const] in nsIntSize aViewportSize,
533 : * in PRUint32 aFlags); */
534 : NS_IMETHODIMP
535 0 : VectorImage::Draw(gfxContext* aContext,
536 : gfxPattern::GraphicsFilter aFilter,
537 : const gfxMatrix& aUserSpaceToImageSpace,
538 : const gfxRect& aFill,
539 : const nsIntRect& aSubimage,
540 : const nsIntSize& aViewportSize,
541 : PRUint32 aFlags)
542 : {
543 0 : NS_ENSURE_ARG_POINTER(aContext);
544 0 : if (mError || !mIsFullyLoaded)
545 0 : return NS_ERROR_FAILURE;
546 :
547 0 : if (mIsDrawing) {
548 0 : NS_WARNING("Refusing to make re-entrant call to VectorImage::Draw");
549 0 : return NS_ERROR_FAILURE;
550 : }
551 0 : mIsDrawing = true;
552 :
553 0 : if (aViewportSize != mLastRenderedSize) {
554 0 : mSVGDocumentWrapper->UpdateViewportBounds(aViewportSize);
555 0 : mLastRenderedSize = aViewportSize;
556 : }
557 0 : mSVGDocumentWrapper->FlushImageTransformInvalidation();
558 :
559 : nsIntSize imageSize = mHaveRestrictedRegion ?
560 0 : mRestrictedRegion.Size() : aViewportSize;
561 :
562 : // XXXdholbert Do we need to convert image size from
563 : // CSS pixels to dev pixels here? (is gfxCallbackDrawable's 2nd arg in dev
564 : // pixels?)
565 0 : gfxIntSize imageSizeGfx(imageSize.width, imageSize.height);
566 :
567 : // Based on imgFrame::Draw
568 0 : gfxRect sourceRect = aUserSpaceToImageSpace.Transform(aFill);
569 0 : gfxRect imageRect(0, 0, imageSize.width, imageSize.height);
570 0 : gfxRect subimage(aSubimage.x, aSubimage.y, aSubimage.width, aSubimage.height);
571 :
572 :
573 : nsRefPtr<gfxDrawingCallback> cb =
574 : new SVGDrawingCallback(mSVGDocumentWrapper,
575 : mHaveRestrictedRegion ?
576 : mRestrictedRegion :
577 : nsIntRect(nsIntPoint(0, 0), aViewportSize),
578 0 : aFlags);
579 :
580 0 : nsRefPtr<gfxDrawable> drawable = new gfxCallbackDrawable(cb, imageSizeGfx);
581 :
582 : gfxUtils::DrawPixelSnapped(aContext, drawable,
583 : aUserSpaceToImageSpace,
584 : subimage, sourceRect, imageRect, aFill,
585 0 : gfxASurface::ImageFormatARGB32, aFilter);
586 :
587 0 : mIsDrawing = false;
588 0 : return NS_OK;
589 : }
590 :
591 : //******************************************************************************
592 : /* [notxpcom] nsIFrame GetRootLayoutFrame() */
593 : nsIFrame*
594 0 : VectorImage::GetRootLayoutFrame()
595 : {
596 0 : if (mError)
597 0 : return nsnull;
598 :
599 0 : return mSVGDocumentWrapper->GetRootLayoutFrame();
600 : }
601 :
602 : //******************************************************************************
603 : /* void requestDecode() */
604 : NS_IMETHODIMP
605 0 : VectorImage::RequestDecode()
606 : {
607 : // Nothing to do for SVG images
608 0 : return NS_OK;
609 : }
610 :
611 : //******************************************************************************
612 : /* void lockImage() */
613 : NS_IMETHODIMP
614 0 : VectorImage::LockImage()
615 : {
616 : // This method is for image-discarding, which only applies to RasterImages.
617 0 : return NS_OK;
618 : }
619 :
620 : //******************************************************************************
621 : /* void unlockImage() */
622 : NS_IMETHODIMP
623 0 : VectorImage::UnlockImage()
624 : {
625 : // This method is for image-discarding, which only applies to RasterImages.
626 0 : return NS_OK;
627 : }
628 :
629 : //******************************************************************************
630 : /* void requestDiscard() */
631 : NS_IMETHODIMP
632 0 : VectorImage::RequestDiscard()
633 : {
634 : // This method is for image-discarding, which only applies to RasterImages.
635 0 : return NS_OK;
636 : }
637 :
638 : //******************************************************************************
639 : /* void resetAnimation (); */
640 : NS_IMETHODIMP
641 0 : VectorImage::ResetAnimation()
642 : {
643 0 : if (mError)
644 0 : return NS_ERROR_FAILURE;
645 :
646 0 : if (!mIsFullyLoaded || !mHaveAnimations) {
647 0 : return NS_OK; // There are no animations to be reset.
648 : }
649 :
650 0 : mSVGDocumentWrapper->ResetAnimation();
651 :
652 0 : return NS_OK;
653 : }
654 :
655 : //------------------------------------------------------------------------------
656 : // nsIRequestObserver methods
657 :
658 : //******************************************************************************
659 : /* void onStartRequest(in nsIRequest request, in nsISupports ctxt); */
660 : NS_IMETHODIMP
661 0 : VectorImage::OnStartRequest(nsIRequest* aRequest, nsISupports* aCtxt)
662 : {
663 0 : NS_ABORT_IF_FALSE(!mSVGDocumentWrapper,
664 : "Repeated call to OnStartRequest -- can this happen?");
665 :
666 0 : mSVGDocumentWrapper = new SVGDocumentWrapper();
667 0 : nsresult rv = mSVGDocumentWrapper->OnStartRequest(aRequest, aCtxt);
668 0 : if (NS_FAILED(rv)) {
669 0 : mSVGDocumentWrapper = nsnull;
670 0 : mError = true;
671 : }
672 :
673 0 : return rv;
674 : }
675 :
676 : //******************************************************************************
677 : /* void onStopRequest(in nsIRequest request, in nsISupports ctxt,
678 : in nsresult status); */
679 : NS_IMETHODIMP
680 0 : VectorImage::OnStopRequest(nsIRequest* aRequest, nsISupports* aCtxt,
681 : nsresult aStatus)
682 : {
683 0 : if (mError)
684 0 : return NS_ERROR_FAILURE;
685 :
686 0 : NS_ABORT_IF_FALSE(!mIsFullyLoaded && !mHaveAnimations,
687 : "these flags shouldn't get set until OnStopRequest. "
688 : "Duplicate calls to OnStopRequest?");
689 :
690 0 : nsresult rv = mSVGDocumentWrapper->OnStopRequest(aRequest, aCtxt, aStatus);
691 0 : if (!mSVGDocumentWrapper->ParsedSuccessfully()) {
692 : // XXXdholbert Need to do something more here -- right now, this just
693 : // makes us draw the "object" icon, rather than the (jagged) "broken image"
694 : // icon. See bug 594505.
695 0 : mError = true;
696 0 : return rv;
697 : }
698 :
699 0 : mIsFullyLoaded = true;
700 0 : mHaveAnimations = mSVGDocumentWrapper->IsAnimated();
701 :
702 : // Start listening to our image for rendering updates
703 0 : mRenderingObserver = new SVGRootRenderingObserver(mSVGDocumentWrapper, this);
704 :
705 : // Tell *our* observers that we're done loading
706 0 : nsCOMPtr<imgIDecoderObserver> observer = do_QueryReferent(mObserver);
707 0 : if (observer) {
708 : // NOTE: This signals that width/height are available.
709 0 : observer->OnStartContainer(nsnull, this);
710 :
711 0 : observer->FrameChanged(nsnull, this, &nsIntRect::GetMaxSizedIntRect());
712 0 : observer->OnStopFrame(nsnull, 0);
713 0 : observer->OnStopDecode(nsnull, NS_OK, nsnull);
714 : }
715 0 : EvaluateAnimation();
716 :
717 0 : return rv;
718 : }
719 :
720 : //------------------------------------------------------------------------------
721 : // nsIStreamListener method
722 :
723 : //******************************************************************************
724 : /* void onDataAvailable(in nsIRequest request, in nsISupports ctxt,
725 : in nsIInputStream inStr, in unsigned long sourceOffset,
726 : in unsigned long count); */
727 : NS_IMETHODIMP
728 0 : VectorImage::OnDataAvailable(nsIRequest* aRequest, nsISupports* aCtxt,
729 : nsIInputStream* aInStr, PRUint32 aSourceOffset,
730 : PRUint32 aCount)
731 : {
732 0 : if (mError)
733 0 : return NS_ERROR_FAILURE;
734 :
735 0 : return mSVGDocumentWrapper->OnDataAvailable(aRequest, aCtxt, aInStr,
736 0 : aSourceOffset, aCount);
737 : }
738 :
739 : // --------------------------
740 : // Invalidation helper method
741 :
742 : void
743 0 : VectorImage::InvalidateObserver()
744 : {
745 0 : if (!mObserver)
746 0 : return;
747 :
748 0 : nsCOMPtr<imgIContainerObserver> containerObs(do_QueryReferent(mObserver));
749 0 : if (containerObs) {
750 0 : containerObs->FrameChanged(nsnull, this, &nsIntRect::GetMaxSizedIntRect());
751 : }
752 :
753 0 : nsCOMPtr<imgIDecoderObserver> decoderObs(do_QueryReferent(mObserver));
754 0 : if (decoderObs) {
755 0 : decoderObs->OnStopFrame(nsnull, imgIContainer::FRAME_CURRENT);
756 : }
757 : }
758 :
759 : } // namespace image
760 : } // namespace mozilla
|