Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / gfx / src / thebes / nsThebesImage.cpp
blob8ba9c10be3cd22a59931e42bda411464b6b10b59
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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.
15 * The Original Code is thebes gfx
17 * The Initial Developer of the Original Code is
18 * mozilla.org.
19 * Portions created by the Initial Developer are Copyright (C) 2005
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Vladimir Vukicevic <vladimir@pobox.com>
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.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsThebesImage.h"
40 #include "nsThebesRenderingContext.h"
42 #include "gfxContext.h"
43 #include "gfxPattern.h"
45 #include "gfxPlatform.h"
47 #include "prenv.h"
49 static PRBool gDisableOptimize = PR_FALSE;
51 #ifdef XP_WIN
52 static PRUint32 gTotalDDBs = 0;
53 static PRUint32 gTotalDDBSize = 0;
54 // only use up a maximum of 64MB in DDBs
55 #define kMaxDDBSize (64*1024*1024)
56 // and don't let anything in that's bigger than 4MB
57 #define kMaxSingleDDBSize (4*1024*1024)
58 #endif
60 NS_IMPL_ISUPPORTS1(nsThebesImage, nsIImage)
62 nsThebesImage::nsThebesImage()
63 : mFormat(gfxImageSurface::ImageFormatRGB24),
64 mWidth(0),
65 mHeight(0),
66 mDecoded(0,0,0,0),
67 mImageComplete(PR_FALSE),
68 mSinglePixel(PR_FALSE),
69 mFormatChanged(PR_FALSE),
70 mAlphaDepth(0)
72 static PRBool hasCheckedOptimize = PR_FALSE;
73 if (!hasCheckedOptimize) {
74 if (PR_GetEnv("MOZ_DISABLE_IMAGE_OPTIMIZE")) {
75 gDisableOptimize = PR_TRUE;
77 hasCheckedOptimize = PR_TRUE;
80 #ifdef XP_WIN
81 mIsDDBSurface = PR_FALSE;
82 #endif
85 nsresult
86 nsThebesImage::Init(PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth, nsMaskRequirements aMaskRequirements)
88 mWidth = aWidth;
89 mHeight = aHeight;
91 // Reject over-wide or over-tall images.
92 if (!AllowedImageSize(aWidth, aHeight))
93 return NS_ERROR_FAILURE;
95 // Check to see if we are running OOM
96 nsCOMPtr<nsIMemory> mem;
97 NS_GetMemoryManager(getter_AddRefs(mem));
98 if (!mem)
99 return NS_ERROR_UNEXPECTED;
101 PRBool lowMemory;
102 mem->IsLowMemory(&lowMemory);
103 if (lowMemory)
104 return NS_ERROR_OUT_OF_MEMORY;
106 gfxImageSurface::gfxImageFormat format;
107 switch(aMaskRequirements)
109 case nsMaskRequirements_kNeeds1Bit:
110 format = gfxImageSurface::ImageFormatARGB32;
111 mAlphaDepth = 1;
112 break;
113 case nsMaskRequirements_kNeeds8Bit:
114 format = gfxImageSurface::ImageFormatARGB32;
115 mAlphaDepth = 8;
116 break;
117 default:
118 format = gfxImageSurface::ImageFormatRGB24;
119 mAlphaDepth = 0;
120 break;
123 mFormat = format;
125 #ifdef XP_WIN
126 if (!ShouldUseImageSurfaces()) {
127 mWinSurface = new gfxWindowsSurface(gfxIntSize(mWidth, mHeight), format);
128 if (mWinSurface && mWinSurface->CairoStatus() == 0) {
129 // no error
130 mImageSurface = mWinSurface->GetImageSurface();
134 if (!mImageSurface)
135 mWinSurface = nsnull;
136 #endif
138 if (!mImageSurface)
139 mImageSurface = new gfxImageSurface(gfxIntSize(mWidth, mHeight), format);
141 if (!mImageSurface || mImageSurface->CairoStatus()) {
142 mImageSurface = nsnull;
143 // guess
144 return NS_ERROR_OUT_OF_MEMORY;
147 #ifdef XP_MACOSX
148 mQuartzSurface = new gfxQuartzImageSurface(mImageSurface);
149 #endif
151 mStride = mImageSurface->Stride();
153 return NS_OK;
156 nsThebesImage::~nsThebesImage()
158 #ifdef XP_WIN
159 if (mIsDDBSurface) {
160 gTotalDDBs--;
161 gTotalDDBSize -= mWidth*mHeight*4;
163 #endif
166 PRInt32
167 nsThebesImage::GetBytesPix()
169 return 4;
172 PRBool
173 nsThebesImage::GetIsRowOrderTopToBottom()
175 return PR_TRUE;
178 PRInt32
179 nsThebesImage::GetWidth()
181 return mWidth;
184 PRInt32
185 nsThebesImage::GetHeight()
187 return mHeight;
190 PRUint8 *
191 nsThebesImage::GetBits()
193 if (mImageSurface)
194 return mImageSurface->Data();
195 return nsnull;
198 PRInt32
199 nsThebesImage::GetLineStride()
201 return mStride;
204 PRBool
205 nsThebesImage::GetHasAlphaMask()
207 return mAlphaDepth > 0;
210 PRUint8 *
211 nsThebesImage::GetAlphaBits()
213 return nsnull;
216 PRInt32
217 nsThebesImage::GetAlphaLineStride()
219 return (mAlphaDepth > 0) ? mStride : 0;
222 nsresult
223 nsThebesImage::ImageUpdated(nsIDeviceContext *aContext, PRUint8 aFlags, nsRect *aUpdateRect)
225 // Check to see if we are running OOM
226 nsCOMPtr<nsIMemory> mem;
227 NS_GetMemoryManager(getter_AddRefs(mem));
228 if (!mem)
229 return NS_ERROR_UNEXPECTED;
231 PRBool lowMemory;
232 mem->IsLowMemory(&lowMemory);
233 if (lowMemory)
234 return NS_ERROR_OUT_OF_MEMORY;
236 mDecoded.UnionRect(mDecoded, *aUpdateRect);
237 #ifdef XP_MACOSX
238 if (mQuartzSurface)
239 mQuartzSurface->Flush();
240 #endif
241 return NS_OK;
244 PRBool
245 nsThebesImage::GetIsImageComplete()
247 if (!mImageComplete)
248 mImageComplete = (mDecoded == nsRect(0, 0, mWidth, mHeight));
249 return mImageComplete;
252 nsresult
253 nsThebesImage::Optimize(nsIDeviceContext* aContext)
255 if (gDisableOptimize)
256 return NS_OK;
258 if (mOptSurface || mSinglePixel)
259 return NS_OK;
261 /* Figure out if the entire image is a constant color */
263 // this should always be true
264 if (mStride == mWidth * 4) {
265 PRUint32 *imgData = (PRUint32*) mImageSurface->Data();
266 PRUint32 firstPixel = * (PRUint32*) imgData;
267 PRUint32 pixelCount = mWidth * mHeight + 1;
269 while (--pixelCount && *imgData++ == firstPixel)
272 if (pixelCount == 0) {
273 // all pixels were the same
274 if (mFormat == gfxImageSurface::ImageFormatARGB32 ||
275 mFormat == gfxImageSurface::ImageFormatRGB24)
277 mSinglePixelColor = gfxRGBA
278 (firstPixel,
279 (mFormat == gfxImageSurface::ImageFormatRGB24 ?
280 gfxRGBA::PACKED_XRGB :
281 gfxRGBA::PACKED_ARGB_PREMULTIPLIED));
283 mSinglePixel = PR_TRUE;
285 // blow away the older surfaces, to release data
287 mImageSurface = nsnull;
288 mOptSurface = nsnull;
289 #ifdef XP_WIN
290 mWinSurface = nsnull;
291 #endif
292 #ifdef XP_MACOSX
293 mQuartzSurface = nsnull;
294 #endif
295 return NS_OK;
299 // if it's not RGB24/ARGB32, don't optimize, but we never hit this at the moment
302 // if we're being forced to use image surfaces due to
303 // resource constraints, don't try to optimize beyond same-pixel.
304 if (ShouldUseImageSurfaces())
305 return NS_OK;
307 mOptSurface = nsnull;
309 #ifdef XP_WIN
310 // we need to special-case windows here, because windows has
311 // a distinction between DIB and DDB and we want to use DDBs as much
312 // as we can.
313 if (mWinSurface) {
314 // Don't do DDBs for large images; see bug 359147
315 // Note that we bother with DDBs at all because they are much faster
316 // on some systems; on others there isn't much of a speed difference
317 // between DIBs and DDBs.
319 // Originally this just limited to 1024x1024; but that still
320 // had us hitting overall total memory usage limits (which was
321 // around 220MB on my intel shared memory system with 2GB RAM
322 // and 16-128mb in use by the video card, so I can't make
323 // heads or tails out of this limit).
325 // So instead, we clamp the max size to 64MB (this limit shuld
326 // be made dynamic based on.. something.. as soon a we figure
327 // out that something) and also limit each individual image to
328 // be less than 4MB to keep very large images out of DDBs.
330 // assume (almost -- we don't quadword-align) worst-case size
331 PRUint32 ddbSize = mWidth * mHeight * 4;
332 if (ddbSize <= kMaxSingleDDBSize &&
333 ddbSize + gTotalDDBSize <= kMaxDDBSize)
335 nsRefPtr<gfxWindowsSurface> wsurf = mWinSurface->OptimizeToDDB(nsnull, gfxIntSize(mWidth, mHeight), mFormat);
336 if (wsurf) {
337 gTotalDDBs++;
338 gTotalDDBSize += ddbSize;
339 mIsDDBSurface = PR_TRUE;
340 mOptSurface = wsurf;
343 if (!mOptSurface && !mFormatChanged) {
344 // just use the DIB if the format has not changed
345 mOptSurface = mWinSurface;
348 #endif
350 #ifdef XP_MACOSX
351 if (mQuartzSurface) {
352 mQuartzSurface->Flush();
353 mOptSurface = mQuartzSurface;
355 #endif
357 if (mOptSurface == nsnull)
358 mOptSurface = gfxPlatform::GetPlatform()->OptimizeImage(mImageSurface, mFormat);
360 if (mOptSurface) {
361 mImageSurface = nsnull;
362 #ifdef XP_WIN
363 mWinSurface = nsnull;
364 #endif
365 #ifdef XP_MACOSX
366 mQuartzSurface = nsnull;
367 #endif
370 return NS_OK;
373 nsColorMap *
374 nsThebesImage::GetColorMap()
376 return NULL;
379 PRInt8
380 nsThebesImage::GetAlphaDepth()
382 return mAlphaDepth;
385 void *
386 nsThebesImage::GetBitInfo()
388 return NULL;
391 NS_IMETHODIMP
392 nsThebesImage::LockImagePixels(PRBool aMaskPixels)
394 if (aMaskPixels)
395 return NS_ERROR_NOT_IMPLEMENTED;
396 if ((mOptSurface || mSinglePixel) && !mImageSurface) {
397 // Recover the pixels
398 mImageSurface = new gfxImageSurface(gfxIntSize(mWidth, mHeight),
399 gfxImageSurface::ImageFormatARGB32);
400 if (!mImageSurface || mImageSurface->CairoStatus())
401 return NS_ERROR_OUT_OF_MEMORY;
402 gfxContext context(mImageSurface);
403 context.SetOperator(gfxContext::OPERATOR_SOURCE);
404 if (mSinglePixel)
405 context.SetDeviceColor(mSinglePixelColor);
406 else
407 context.SetSource(mOptSurface);
408 context.Paint();
410 #ifdef XP_WIN
411 mWinSurface = nsnull;
412 #endif
413 #ifdef XP_MACOSX
414 mQuartzSurface = nsnull;
415 #endif
418 return NS_OK;
421 NS_IMETHODIMP
422 nsThebesImage::UnlockImagePixels(PRBool aMaskPixels)
424 if (aMaskPixels)
425 return NS_ERROR_NOT_IMPLEMENTED;
426 mOptSurface = nsnull;
427 #ifdef XP_MACOSX
428 if (mQuartzSurface)
429 mQuartzSurface->Flush();
430 #endif
431 return NS_OK;
434 static PRBool
435 IsSafeImageTransformComponent(gfxFloat aValue)
437 return aValue >= -32768 && aValue <= 32767;
440 void
441 nsThebesImage::Draw(gfxContext* aContext,
442 const gfxMatrix& aUserSpaceToImageSpace,
443 const gfxRect& aFill,
444 const nsIntMargin& aPadding,
445 const nsIntRect& aSubimage)
447 NS_ASSERTION(!aFill.IsEmpty(), "zero dest size --- fix caller");
448 NS_ASSERTION(!aSubimage.IsEmpty(), "zero source size --- fix caller");
450 PRBool doPadding = aPadding != nsIntMargin(0,0,0,0);
451 PRBool doPartialDecode = !GetIsImageComplete();
452 gfxContext::GraphicsOperator op = aContext->CurrentOperator();
454 if (mSinglePixel && !doPadding && !doPartialDecode) {
455 // Single-color fast path
456 // if a == 0, it's a noop
457 if (mSinglePixelColor.a == 0.0)
458 return;
460 if (op == gfxContext::OPERATOR_OVER && mSinglePixelColor.a == 1.0)
461 aContext->SetOperator(gfxContext::OPERATOR_SOURCE);
463 aContext->SetDeviceColor(mSinglePixelColor);
464 aContext->NewPath();
465 aContext->Rectangle(aFill);
466 aContext->Fill();
467 aContext->SetOperator(op);
468 aContext->SetDeviceColor(gfxRGBA(0,0,0,0));
469 return;
472 gfxMatrix userSpaceToImageSpace = aUserSpaceToImageSpace;
473 gfxRect sourceRect = userSpaceToImageSpace.Transform(aFill);
474 gfxRect imageRect(0, 0, mWidth + aPadding.LeftRight(), mHeight + aPadding.TopBottom());
475 gfxRect subimage(aSubimage.x, aSubimage.y, aSubimage.width, aSubimage.height);
476 gfxRect fill = aFill;
477 nsRefPtr<gfxASurface> surface;
478 gfxImageSurface::gfxImageFormat format;
480 NS_ASSERTION(!sourceRect.Intersect(subimage).IsEmpty(),
481 "We must be allowed to sample *some* source pixels!");
483 PRBool doTile = !imageRect.Contains(sourceRect);
484 if (doPadding || doPartialDecode) {
485 gfxRect available = gfxRect(mDecoded.x, mDecoded.y, mDecoded.width, mDecoded.height) +
486 gfxPoint(aPadding.left, aPadding.top);
488 if (!doTile && !mSinglePixel) {
489 // Not tiling, and we have a surface, so we can account for
490 // padding and/or a partial decode just by twiddling parameters.
491 // First, update our user-space fill rect.
492 sourceRect = sourceRect.Intersect(available);
493 gfxMatrix imageSpaceToUserSpace = userSpaceToImageSpace;
494 imageSpaceToUserSpace.Invert();
495 fill = imageSpaceToUserSpace.Transform(sourceRect);
497 surface = ThebesSurface();
498 format = mFormat;
499 subimage = subimage.Intersect(available) - gfxPoint(aPadding.left, aPadding.top);
500 userSpaceToImageSpace.Multiply(
501 gfxMatrix().Translate(-gfxPoint(aPadding.left, aPadding.top)));
502 sourceRect = sourceRect - gfxPoint(aPadding.left, aPadding.top);
503 imageRect = gfxRect(0, 0, mWidth, mHeight);
504 } else {
505 // Create a temporary surface
506 gfxIntSize size(PRInt32(imageRect.Width()),
507 PRInt32(imageRect.Height()));
508 // Give this surface an alpha channel because there are
509 // transparent pixels in the padding or undecoded area
510 format = gfxASurface::ImageFormatARGB32;
511 surface = gfxPlatform::GetPlatform()->CreateOffscreenSurface(size,
512 format);
513 if (!surface || surface->CairoStatus() != 0)
514 return;
516 // Fill 'available' with whatever we've got
517 gfxContext tmpCtx(surface);
518 tmpCtx.SetOperator(gfxContext::OPERATOR_SOURCE);
519 if (mSinglePixel) {
520 tmpCtx.SetDeviceColor(mSinglePixelColor);
521 } else {
522 tmpCtx.SetSource(ThebesSurface(), gfxPoint(aPadding.left, aPadding.top));
524 tmpCtx.Rectangle(available);
525 tmpCtx.Fill();
527 } else {
528 NS_ASSERTION(!mSinglePixel, "This should already have been handled");
529 surface = ThebesSurface();
530 format = mFormat;
532 // At this point, we've taken care of mSinglePixel images, images with
533 // aPadding, and partially-decoded images.
535 if (!AllowedImageSize(fill.size.width + 1, fill.size.height + 1)) {
536 NS_WARNING("Destination area too large, bailing out");
537 return;
540 // BEGIN working around cairo/pixman bug (bug 364968)
541 // Compute device-space-to-image-space transform. We need to sanity-
542 // check it to work around a pixman bug :-(
543 // XXX should we only do this for certain surface types?
544 gfxFloat deviceX, deviceY;
545 nsRefPtr<gfxASurface> currentTarget =
546 aContext->CurrentSurface(&deviceX, &deviceY);
547 gfxMatrix currentMatrix = aContext->CurrentMatrix();
548 gfxMatrix deviceToUser = currentMatrix;
549 deviceToUser.Invert();
550 deviceToUser.Translate(-gfxPoint(-deviceX, -deviceY));
551 gfxMatrix deviceToImage = deviceToUser;
552 deviceToImage.Multiply(userSpaceToImageSpace);
554 // Our device-space-to-image-space transform may not be acceptable to pixman.
555 if (!IsSafeImageTransformComponent(deviceToImage.xx) ||
556 !IsSafeImageTransformComponent(deviceToImage.xy) ||
557 !IsSafeImageTransformComponent(deviceToImage.yx) ||
558 !IsSafeImageTransformComponent(deviceToImage.yy)) {
559 NS_WARNING("Scaling up too much, bailing out");
560 return;
563 PRBool pushedGroup = PR_FALSE;
564 if (!IsSafeImageTransformComponent(deviceToImage.x0) ||
565 !IsSafeImageTransformComponent(deviceToImage.y0)) {
566 // We'll push a group, which will hopefully reduce our transform's
567 // translation so it's in bounds
568 aContext->Save();
570 // Clip the rounded-out-to-device-pixels bounds of the
571 // transformed fill area. This is the area for the group we
572 // want to push.
573 aContext->IdentityMatrix();
574 gfxRect bounds = currentMatrix.TransformBounds(fill);
575 bounds.RoundOut();
576 aContext->Clip(bounds);
577 aContext->SetMatrix(currentMatrix);
579 aContext->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
580 aContext->SetOperator(gfxContext::OPERATOR_OVER);
581 pushedGroup = PR_TRUE;
583 // END working around cairo/pixman bug (bug 364968)
585 nsRefPtr<gfxPattern> pattern = new gfxPattern(surface);
586 pattern->SetMatrix(userSpaceToImageSpace);
588 // OK now, the hard part left is to account for the subimage sampling
589 // restriction. If all the transforms involved are just integer
590 // translations, then we assume no resampling will occur so there's
591 // nothing to do.
592 // XXX if only we had source-clipping in cairo!
593 if (!currentMatrix.HasNonIntegerTranslation() &&
594 !userSpaceToImageSpace.HasNonIntegerTranslation()) {
595 if (doTile) {
596 pattern->SetExtend(gfxPattern::EXTEND_REPEAT);
598 } else {
599 if (doTile || !subimage.Contains(imageRect)) {
600 // EXTEND_PAD won't help us here; we have to create a temporary
601 // surface to hold the subimage of pixels we're allowed to
602 // sample
603 gfxRect needed = subimage.Intersect(sourceRect);
604 needed.RoundOut();
605 gfxIntSize size(PRInt32(needed.Width()), PRInt32(needed.Height()));
606 NS_ASSERTION(size.width > 0 && size.height > 0,
607 "We must have some needed pixels, otherwise we don't know what to sample");
608 nsRefPtr<gfxASurface> temp =
609 gfxPlatform::GetPlatform()->CreateOffscreenSurface(size, format);
610 if (temp && temp->CairoStatus() == 0) {
611 gfxContext tmpCtx(temp);
612 tmpCtx.SetOperator(gfxContext::OPERATOR_SOURCE);
613 nsRefPtr<gfxPattern> tmpPattern = new gfxPattern(surface);
614 if (tmpPattern) {
615 tmpPattern->SetExtend(gfxPattern::EXTEND_REPEAT);
616 tmpPattern->SetMatrix(gfxMatrix().Translate(needed.pos));
617 tmpCtx.SetPattern(tmpPattern);
618 tmpCtx.Paint();
619 tmpPattern = new gfxPattern(temp);
620 if (tmpPattern) {
621 pattern.swap(tmpPattern);
622 pattern->SetMatrix(
623 gfxMatrix(userSpaceToImageSpace).Multiply(gfxMatrix().Translate(-needed.pos)));
629 // In theory we can handle this using cairo's EXTEND_PAD,
630 // but implementation limitations mean we have to consult
631 // the surface type.
632 switch (currentTarget->GetType()) {
633 case gfxASurface::SurfaceTypeXlib:
634 case gfxASurface::SurfaceTypeXcb: {
635 // See bug 324698. This is a workaround for EXTEND_PAD not being
636 // implemented correctly on linux in the X server.
638 // Set the filter to CAIRO_FILTER_FAST --- otherwise,
639 // pixman's sampling will sample transparency for the outside edges and we'll
640 // get blurry edges. CAIRO_EXTEND_PAD would also work here, if
641 // available
643 // But don't do this for simple downscales because it's horrible.
644 // Downscaling means that device-space coordinates are
645 // scaled *up* to find the image pixel coordinates.
647 // deviceToImage is slightly stale because up above we may
648 // have adjusted the pattern's matrix ... but the adjustment
649 // is only a translation so the scale factors in deviceToImage
650 // are still valid.
651 PRBool isDownscale =
652 deviceToImage.xx >= 1.0 && deviceToImage.yy >= 1.0 &&
653 deviceToImage.xy == 0.0 && deviceToImage.yx == 0.0;
654 if (!isDownscale) {
655 pattern->SetFilter(0);
657 break;
660 case gfxASurface::SurfaceTypeQuartz:
661 case gfxASurface::SurfaceTypeQuartzImage:
662 // Do nothing, Mac seems to be OK. Really?
663 break;
665 default:
666 // turn on EXTEND_PAD.
667 // This is what we really want for all surface types, if the
668 // implementation was universally good.
669 pattern->SetExtend(gfxPattern::EXTEND_PAD);
670 break;
674 if ((op == gfxContext::OPERATOR_OVER || pushedGroup) &&
675 format == gfxASurface::ImageFormatRGB24) {
676 aContext->SetOperator(gfxContext::OPERATOR_SOURCE);
679 // Phew! Now we can actually draw this image
680 aContext->NewPath();
681 aContext->SetPattern(pattern);
682 aContext->Rectangle(fill);
683 aContext->Fill();
685 aContext->SetOperator(op);
686 if (pushedGroup) {
687 aContext->PopGroupToSource();
688 aContext->Paint();
689 aContext->Restore();
693 PRBool
694 nsThebesImage::ShouldUseImageSurfaces()
696 #if defined(WINCE)
697 // There is no test on windows mobile to check for Gui resources.
698 // Allocate, until we run out of memory.
699 return PR_TRUE;
701 #elif defined(XP_WIN)
702 static const DWORD kGDIObjectsHighWaterMark = 7000;
704 // at 7000 GDI objects, stop allocating normal images to make sure
705 // we never hit the 10k hard limit.
706 // GetCurrentProcess() just returns (HANDLE)-1, it's inlined afaik
707 DWORD count = GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS);
708 if (count == 0 ||
709 count > kGDIObjectsHighWaterMark)
711 // either something's broken (count == 0),
712 // or we hit our high water mark; disable
713 // image allocations for a bit.
714 return PR_TRUE;
716 #endif
718 return PR_FALSE;
721 // A hint from the image decoders that this image has no alpha, even
722 // though we created is ARGB32. This changes our format to RGB24,
723 // which in turn will cause us to Optimize() to RGB24. Has no effect
724 // after Optimize() is called, though in all cases it will be just a
725 // performance win -- the pixels are still correct and have the A byte
726 // set to 0xff.
727 void
728 nsThebesImage::SetHasNoAlpha()
730 if (mFormat == gfxASurface::ImageFormatARGB32) {
731 mFormat = gfxASurface::ImageFormatRGB24;
732 mFormatChanged = PR_TRUE;