LCOV - code coverage report
Current view: directory - gfx/thebes - gfxUtils.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 229 3 1.3 %
Date: 2012-06-02 Functions: 31 2 6.5 %

       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
       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 Corporation code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is Mozilla Foundation.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2010
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *   Vladimir Vukicevic <vladimir@pobox.com>
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      26                 :  * 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                 : #include "gfxUtils.h"
      39                 : #include "gfxContext.h"
      40                 : #include "gfxPlatform.h"
      41                 : #include "gfxDrawable.h"
      42                 : #include "nsRegion.h"
      43                 : #include "yuv_convert.h"
      44                 : #include "ycbcr_to_rgb565.h"
      45                 : 
      46                 : #ifdef XP_WIN
      47                 : #include "gfxWindowsPlatform.h"
      48                 : #endif
      49                 : 
      50                 : using namespace mozilla;
      51                 : using namespace mozilla::layers;
      52                 : using namespace mozilla::gfx;
      53                 : 
      54                 : static PRUint8 sUnpremultiplyTable[256*256];
      55                 : static PRUint8 sPremultiplyTable[256*256];
      56                 : static bool sTablesInitialized = false;
      57                 : 
      58               0 : static const PRUint8 PremultiplyValue(PRUint8 a, PRUint8 v) {
      59               0 :     return sPremultiplyTable[a*256+v];
      60                 : }
      61                 : 
      62               0 : static const PRUint8 UnpremultiplyValue(PRUint8 a, PRUint8 v) {
      63               0 :     return sUnpremultiplyTable[a*256+v];
      64                 : }
      65                 : 
      66                 : static void
      67               0 : CalculateTables()
      68                 : {
      69                 :     // It's important that the array be indexed first by alpha and then by rgb
      70                 :     // value.  When we unpremultiply a pixel, we're guaranteed to do three
      71                 :     // lookups with the same alpha; indexing by alpha first makes it likely that
      72                 :     // those three lookups will be close to one another in memory, thus
      73                 :     // increasing the chance of a cache hit.
      74                 : 
      75                 :     // Unpremultiply table
      76                 : 
      77                 :     // a == 0 case
      78               0 :     for (PRUint32 c = 0; c <= 255; c++) {
      79               0 :         sUnpremultiplyTable[c] = c;
      80                 :     }
      81                 : 
      82               0 :     for (int a = 1; a <= 255; a++) {
      83               0 :         for (int c = 0; c <= 255; c++) {
      84               0 :             sUnpremultiplyTable[a*256+c] = (PRUint8)((c * 255) / a);
      85                 :         }
      86                 :     }
      87                 : 
      88                 :     // Premultiply table
      89                 : 
      90               0 :     for (int a = 0; a <= 255; a++) {
      91               0 :         for (int c = 0; c <= 255; c++) {
      92               0 :             sPremultiplyTable[a*256+c] = (a * c + 254) / 255;
      93                 :         }
      94                 :     }
      95                 : 
      96               0 :     sTablesInitialized = true;
      97               0 : }
      98                 : 
      99                 : void
     100               0 : gfxUtils::PremultiplyImageSurface(gfxImageSurface *aSourceSurface,
     101                 :                                   gfxImageSurface *aDestSurface)
     102                 : {
     103               0 :     if (!aDestSurface)
     104               0 :         aDestSurface = aSourceSurface;
     105                 : 
     106               0 :     NS_ASSERTION(aSourceSurface->Format() == aDestSurface->Format() &&
     107                 :                  aSourceSurface->Width() == aDestSurface->Width() &&
     108                 :                  aSourceSurface->Height() == aDestSurface->Height() &&
     109                 :                  aSourceSurface->Stride() == aDestSurface->Stride(),
     110                 :                  "Source and destination surfaces don't have identical characteristics");
     111                 : 
     112               0 :     NS_ASSERTION(aSourceSurface->Stride() == aSourceSurface->Width() * 4,
     113                 :                  "Source surface stride isn't tightly packed");
     114                 : 
     115                 :     // Only premultiply ARGB32
     116               0 :     if (aSourceSurface->Format() != gfxASurface::ImageFormatARGB32) {
     117               0 :         if (aDestSurface != aSourceSurface) {
     118               0 :             memcpy(aDestSurface->Data(), aSourceSurface->Data(),
     119               0 :                    aSourceSurface->Stride() * aSourceSurface->Height());
     120                 :         }
     121               0 :         return;
     122                 :     }
     123                 : 
     124               0 :     if (!sTablesInitialized)
     125               0 :         CalculateTables();
     126                 : 
     127               0 :     PRUint8 *src = aSourceSurface->Data();
     128               0 :     PRUint8 *dst = aDestSurface->Data();
     129                 : 
     130               0 :     PRUint32 dim = aSourceSurface->Width() * aSourceSurface->Height();
     131               0 :     for (PRUint32 i = 0; i < dim; ++i) {
     132                 : #ifdef IS_LITTLE_ENDIAN
     133               0 :         PRUint8 b = *src++;
     134               0 :         PRUint8 g = *src++;
     135               0 :         PRUint8 r = *src++;
     136               0 :         PRUint8 a = *src++;
     137                 : 
     138               0 :         *dst++ = PremultiplyValue(a, b);
     139               0 :         *dst++ = PremultiplyValue(a, g);
     140               0 :         *dst++ = PremultiplyValue(a, r);
     141               0 :         *dst++ = a;
     142                 : #else
     143                 :         PRUint8 a = *src++;
     144                 :         PRUint8 r = *src++;
     145                 :         PRUint8 g = *src++;
     146                 :         PRUint8 b = *src++;
     147                 : 
     148                 :         *dst++ = a;
     149                 :         *dst++ = PremultiplyValue(a, r);
     150                 :         *dst++ = PremultiplyValue(a, g);
     151                 :         *dst++ = PremultiplyValue(a, b);
     152                 : #endif
     153                 :     }
     154                 : }
     155                 : 
     156                 : void
     157               0 : gfxUtils::UnpremultiplyImageSurface(gfxImageSurface *aSourceSurface,
     158                 :                                     gfxImageSurface *aDestSurface)
     159                 : {
     160               0 :     if (!aDestSurface)
     161               0 :         aDestSurface = aSourceSurface;
     162                 : 
     163               0 :     NS_ASSERTION(aSourceSurface->Format() == aDestSurface->Format() &&
     164                 :                  aSourceSurface->Width() == aDestSurface->Width() &&
     165                 :                  aSourceSurface->Height() == aDestSurface->Height() &&
     166                 :                  aSourceSurface->Stride() == aDestSurface->Stride(),
     167                 :                  "Source and destination surfaces don't have identical characteristics");
     168                 : 
     169               0 :     NS_ASSERTION(aSourceSurface->Stride() == aSourceSurface->Width() * 4,
     170                 :                  "Source surface stride isn't tightly packed");
     171                 : 
     172                 :     // Only premultiply ARGB32
     173               0 :     if (aSourceSurface->Format() != gfxASurface::ImageFormatARGB32) {
     174               0 :         if (aDestSurface != aSourceSurface) {
     175               0 :             memcpy(aDestSurface->Data(), aSourceSurface->Data(),
     176               0 :                    aSourceSurface->Stride() * aSourceSurface->Height());
     177                 :         }
     178               0 :         return;
     179                 :     }
     180                 : 
     181               0 :     if (!sTablesInitialized)
     182               0 :         CalculateTables();
     183                 : 
     184               0 :     PRUint8 *src = aSourceSurface->Data();
     185               0 :     PRUint8 *dst = aDestSurface->Data();
     186                 : 
     187               0 :     PRUint32 dim = aSourceSurface->Width() * aSourceSurface->Height();
     188               0 :     for (PRUint32 i = 0; i < dim; ++i) {
     189                 : #ifdef IS_LITTLE_ENDIAN
     190               0 :         PRUint8 b = *src++;
     191               0 :         PRUint8 g = *src++;
     192               0 :         PRUint8 r = *src++;
     193               0 :         PRUint8 a = *src++;
     194                 : 
     195               0 :         *dst++ = UnpremultiplyValue(a, b);
     196               0 :         *dst++ = UnpremultiplyValue(a, g);
     197               0 :         *dst++ = UnpremultiplyValue(a, r);
     198               0 :         *dst++ = a;
     199                 : #else
     200                 :         PRUint8 a = *src++;
     201                 :         PRUint8 r = *src++;
     202                 :         PRUint8 g = *src++;
     203                 :         PRUint8 b = *src++;
     204                 : 
     205                 :         *dst++ = a;
     206                 :         *dst++ = UnpremultiplyValue(a, r);
     207                 :         *dst++ = UnpremultiplyValue(a, g);
     208                 :         *dst++ = UnpremultiplyValue(a, b);
     209                 : #endif
     210                 :     }
     211                 : }
     212                 : 
     213                 : static bool
     214               0 : IsSafeImageTransformComponent(gfxFloat aValue)
     215                 : {
     216               0 :   return aValue >= -32768 && aValue <= 32767;
     217                 : }
     218                 : 
     219                 : /**
     220                 :  * This returns the fastest operator to use for solid surfaces which have no
     221                 :  * alpha channel or their alpha channel is uniformly opaque.
     222                 :  * This differs per render mode.
     223                 :  */
     224                 : static gfxContext::GraphicsOperator
     225               0 : OptimalFillOperator()
     226                 : {
     227                 : #ifdef XP_WIN
     228                 :     if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
     229                 :         gfxWindowsPlatform::RENDER_DIRECT2D) {
     230                 :         // D2D -really- hates operator source.
     231                 :         return gfxContext::OPERATOR_OVER;
     232                 :     } else {
     233                 : #endif
     234               0 :         return gfxContext::OPERATOR_SOURCE;
     235                 : #ifdef XP_WIN
     236                 :     }
     237                 : #endif
     238                 : }
     239                 : 
     240                 : // EXTEND_PAD won't help us here; we have to create a temporary surface to hold
     241                 : // the subimage of pixels we're allowed to sample.
     242                 : static already_AddRefed<gfxDrawable>
     243               0 : CreateSamplingRestrictedDrawable(gfxDrawable* aDrawable,
     244                 :                                  gfxContext* aContext,
     245                 :                                  const gfxMatrix& aUserSpaceToImageSpace,
     246                 :                                  const gfxRect& aSourceRect,
     247                 :                                  const gfxRect& aSubimage,
     248                 :                                  const gfxImageSurface::gfxImageFormat aFormat)
     249                 : {
     250               0 :     gfxRect userSpaceClipExtents = aContext->GetClipExtents();
     251                 :     // This isn't optimal --- if aContext has a rotation then GetClipExtents
     252                 :     // will have to do a bounding-box computation, and TransformBounds might
     253                 :     // too, so we could get a better result if we computed image space clip
     254                 :     // extents in one go --- but it doesn't really matter and this is easier
     255                 :     // to understand.
     256                 :     gfxRect imageSpaceClipExtents =
     257               0 :         aUserSpaceToImageSpace.TransformBounds(userSpaceClipExtents);
     258                 :     // Inflate by one pixel because bilinear filtering will sample at most
     259                 :     // one pixel beyond the computed image pixel coordinate.
     260               0 :     imageSpaceClipExtents.Inflate(1.0);
     261                 : 
     262               0 :     gfxRect needed = imageSpaceClipExtents.Intersect(aSourceRect);
     263               0 :     needed = needed.Intersect(aSubimage);
     264               0 :     needed.RoundOut();
     265                 : 
     266                 :     // if 'needed' is empty, nothing will be drawn since aFill
     267                 :     // must be entirely outside the clip region, so it doesn't
     268                 :     // matter what we do here, but we should avoid trying to
     269                 :     // create a zero-size surface.
     270               0 :     if (needed.IsEmpty())
     271               0 :         return nsnull;
     272                 : 
     273               0 :     gfxIntSize size(PRInt32(needed.Width()), PRInt32(needed.Height()));
     274                 :     nsRefPtr<gfxASurface> temp =
     275               0 :         gfxPlatform::GetPlatform()->CreateOffscreenSurface(size, gfxASurface::ContentFromFormat(aFormat));
     276               0 :     if (!temp || temp->CairoStatus())
     277               0 :         return nsnull;
     278                 : 
     279               0 :     nsRefPtr<gfxContext> tmpCtx = new gfxContext(temp);
     280               0 :     tmpCtx->SetOperator(OptimalFillOperator());
     281               0 :     aDrawable->Draw(tmpCtx, needed - needed.TopLeft(), true,
     282               0 :                     gfxPattern::FILTER_FAST, gfxMatrix().Translate(needed.TopLeft()));
     283                 : 
     284               0 :     nsRefPtr<gfxPattern> resultPattern = new gfxPattern(temp);
     285               0 :     if (!resultPattern)
     286               0 :         return nsnull;
     287                 : 
     288                 :     nsRefPtr<gfxDrawable> drawable = 
     289               0 :         new gfxSurfaceDrawable(temp, size, gfxMatrix().Translate(-needed.TopLeft()));
     290               0 :     return drawable.forget();
     291                 : }
     292                 : 
     293                 : // working around cairo/pixman bug (bug 364968)
     294                 : // Our device-space-to-image-space transform may not be acceptable to pixman.
     295                 : struct NS_STACK_CLASS AutoCairoPixmanBugWorkaround
     296                 : {
     297               0 :     AutoCairoPixmanBugWorkaround(gfxContext*      aContext,
     298                 :                                  const gfxMatrix& aDeviceSpaceToImageSpace,
     299                 :                                  const gfxRect&   aFill,
     300                 :                                  const gfxASurface* aSurface)
     301               0 :      : mContext(aContext), mSucceeded(true), mPushedGroup(false)
     302                 :     {
     303                 :         // Quartz's limits for matrix are much larger than pixman
     304               0 :         if (!aSurface || aSurface->GetType() == gfxASurface::SurfaceTypeQuartz)
     305               0 :             return;
     306                 : 
     307               0 :         if (!IsSafeImageTransformComponent(aDeviceSpaceToImageSpace.xx) ||
     308               0 :             !IsSafeImageTransformComponent(aDeviceSpaceToImageSpace.xy) ||
     309               0 :             !IsSafeImageTransformComponent(aDeviceSpaceToImageSpace.yx) ||
     310               0 :             !IsSafeImageTransformComponent(aDeviceSpaceToImageSpace.yy)) {
     311               0 :             NS_WARNING("Scaling up too much, bailing out");
     312               0 :             mSucceeded = false;
     313               0 :             return;
     314                 :         }
     315                 : 
     316               0 :         if (IsSafeImageTransformComponent(aDeviceSpaceToImageSpace.x0) &&
     317               0 :             IsSafeImageTransformComponent(aDeviceSpaceToImageSpace.y0))
     318               0 :             return;
     319                 : 
     320                 :         // We'll push a group, which will hopefully reduce our transform's
     321                 :         // translation so it's in bounds.
     322               0 :         gfxMatrix currentMatrix = mContext->CurrentMatrix();
     323               0 :         mContext->Save();
     324                 : 
     325                 :         // Clip the rounded-out-to-device-pixels bounds of the
     326                 :         // transformed fill area. This is the area for the group we
     327                 :         // want to push.
     328               0 :         mContext->IdentityMatrix();
     329               0 :         gfxRect bounds = currentMatrix.TransformBounds(aFill);
     330               0 :         bounds.RoundOut();
     331               0 :         mContext->Clip(bounds);
     332               0 :         mContext->SetMatrix(currentMatrix);
     333               0 :         mContext->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
     334               0 :         mContext->SetOperator(gfxContext::OPERATOR_OVER);
     335                 : 
     336               0 :         mPushedGroup = true;
     337                 :     }
     338                 : 
     339               0 :     ~AutoCairoPixmanBugWorkaround()
     340                 :     {
     341               0 :         if (mPushedGroup) {
     342               0 :             mContext->PopGroupToSource();
     343               0 :             mContext->Paint();
     344               0 :             mContext->Restore();
     345                 :         }
     346               0 :     }
     347                 : 
     348               0 :     bool PushedGroup() { return mPushedGroup; }
     349               0 :     bool Succeeded() { return mSucceeded; }
     350                 : 
     351                 : private:
     352                 :     gfxContext* mContext;
     353                 :     bool mSucceeded;
     354                 :     bool mPushedGroup;
     355                 : };
     356                 : 
     357                 : static gfxMatrix
     358               0 : DeviceToImageTransform(gfxContext* aContext,
     359                 :                        const gfxMatrix& aUserSpaceToImageSpace)
     360                 : {
     361                 :     gfxFloat deviceX, deviceY;
     362                 :     nsRefPtr<gfxASurface> currentTarget =
     363               0 :         aContext->CurrentSurface(&deviceX, &deviceY);
     364               0 :     gfxMatrix currentMatrix = aContext->CurrentMatrix();
     365               0 :     gfxMatrix deviceToUser = gfxMatrix(currentMatrix).Invert();
     366               0 :     deviceToUser.Translate(-gfxPoint(-deviceX, -deviceY));
     367               0 :     return gfxMatrix(deviceToUser).Multiply(aUserSpaceToImageSpace);
     368                 : }
     369                 : 
     370                 : /* static */ void
     371               0 : gfxUtils::DrawPixelSnapped(gfxContext*      aContext,
     372                 :                            gfxDrawable*     aDrawable,
     373                 :                            const gfxMatrix& aUserSpaceToImageSpace,
     374                 :                            const gfxRect&   aSubimage,
     375                 :                            const gfxRect&   aSourceRect,
     376                 :                            const gfxRect&   aImageRect,
     377                 :                            const gfxRect&   aFill,
     378                 :                            const gfxImageSurface::gfxImageFormat aFormat,
     379                 :                            const gfxPattern::GraphicsFilter& aFilter)
     380                 : {
     381               0 :     bool doTile = !aImageRect.Contains(aSourceRect);
     382                 : 
     383               0 :     nsRefPtr<gfxASurface> currentTarget = aContext->CurrentSurface();
     384                 :     gfxMatrix deviceSpaceToImageSpace =
     385               0 :         DeviceToImageTransform(aContext, aUserSpaceToImageSpace);
     386                 : 
     387                 :     AutoCairoPixmanBugWorkaround workaround(aContext, deviceSpaceToImageSpace,
     388               0 :                                             aFill, currentTarget);
     389               0 :     if (!workaround.Succeeded())
     390                 :         return;
     391                 : 
     392               0 :     nsRefPtr<gfxDrawable> drawable = aDrawable;
     393                 : 
     394                 :     // OK now, the hard part left is to account for the subimage sampling
     395                 :     // restriction. If all the transforms involved are just integer
     396                 :     // translations, then we assume no resampling will occur so there's
     397                 :     // nothing to do.
     398                 :     // XXX if only we had source-clipping in cairo!
     399               0 :     if (aContext->CurrentMatrix().HasNonIntegerTranslation() ||
     400               0 :         aUserSpaceToImageSpace.HasNonIntegerTranslation()) {
     401               0 :         if (doTile || !aSubimage.Contains(aImageRect)) {
     402                 :             nsRefPtr<gfxDrawable> restrictedDrawable =
     403                 :               CreateSamplingRestrictedDrawable(aDrawable, aContext,
     404                 :                                                aUserSpaceToImageSpace, aSourceRect,
     405               0 :                                                aSubimage, aFormat);
     406               0 :             if (restrictedDrawable) {
     407               0 :                 drawable.swap(restrictedDrawable);
     408                 :             }
     409                 :         }
     410                 :         // We no longer need to tile: Either we never needed to, or we already
     411                 :         // filled a surface with the tiled pattern; this surface can now be
     412                 :         // drawn without tiling.
     413               0 :         doTile = false;
     414                 :     }
     415                 : 
     416               0 :     gfxContext::GraphicsOperator op = aContext->CurrentOperator();
     417               0 :     if ((op == gfxContext::OPERATOR_OVER || workaround.PushedGroup()) &&
     418                 :         aFormat == gfxASurface::ImageFormatRGB24) {
     419               0 :         aContext->SetOperator(OptimalFillOperator());
     420                 :     }
     421                 : 
     422               0 :     drawable->Draw(aContext, aFill, doTile, aFilter, aUserSpaceToImageSpace);
     423                 : 
     424               0 :     aContext->SetOperator(op);
     425                 : }
     426                 : 
     427                 : /* static */ int
     428               0 : gfxUtils::ImageFormatToDepth(gfxASurface::gfxImageFormat aFormat)
     429                 : {
     430               0 :     switch (aFormat) {
     431                 :         case gfxASurface::ImageFormatARGB32:
     432               0 :             return 32;
     433                 :         case gfxASurface::ImageFormatRGB24:
     434               0 :             return 24;
     435                 :         case gfxASurface::ImageFormatRGB16_565:
     436               0 :             return 16;
     437                 :         default:
     438                 :             break;
     439                 :     }
     440               0 :     return 0;
     441                 : }
     442                 : 
     443                 : static void
     444               0 : PathFromRegionInternal(gfxContext* aContext, const nsIntRegion& aRegion,
     445                 :                        bool aSnap)
     446                 : {
     447               0 :   aContext->NewPath();
     448               0 :   nsIntRegionRectIterator iter(aRegion);
     449                 :   const nsIntRect* r;
     450               0 :   while ((r = iter.Next()) != nsnull) {
     451               0 :     aContext->Rectangle(gfxRect(r->x, r->y, r->width, r->height), aSnap);
     452                 :   }
     453               0 : }
     454                 : 
     455                 : static void
     456               0 : ClipToRegionInternal(gfxContext* aContext, const nsIntRegion& aRegion,
     457                 :                      bool aSnap)
     458                 : {
     459               0 :   PathFromRegionInternal(aContext, aRegion, aSnap);
     460               0 :   aContext->Clip();
     461               0 : }
     462                 : 
     463                 : /*static*/ void
     464               0 : gfxUtils::ClipToRegion(gfxContext* aContext, const nsIntRegion& aRegion)
     465                 : {
     466               0 :   ClipToRegionInternal(aContext, aRegion, false);
     467               0 : }
     468                 : 
     469                 : /*static*/ void
     470               0 : gfxUtils::ClipToRegionSnapped(gfxContext* aContext, const nsIntRegion& aRegion)
     471                 : {
     472               0 :   ClipToRegionInternal(aContext, aRegion, true);
     473               0 : }
     474                 : 
     475                 : /*static*/ gfxFloat
     476               0 : gfxUtils::ClampToScaleFactor(gfxFloat aVal)
     477                 : {
     478                 :   // Arbitary scale factor limitation. We can increase this
     479                 :   // for better scaling performance at the cost of worse
     480                 :   // quality.
     481                 :   static const gfxFloat kScaleResolution = 2;
     482                 : 
     483                 :   // Negative scaling is just a flip and irrelevant to
     484                 :   // our resolution calculation.
     485               0 :   if (aVal < 0.0) {
     486               0 :     aVal = -aVal;
     487                 :   }
     488                 : 
     489               0 :   gfxFloat power = log(aVal)/log(kScaleResolution);
     490                 : 
     491                 :   // If power is within 1e-6 of an integer, round to nearest to
     492                 :   // prevent floating point errors, otherwise round up to the
     493                 :   // next integer value.
     494               0 :   if (fabs(power - NS_round(power)) < 1e-6) {
     495               0 :     power = NS_round(power);
     496                 :   } else {
     497               0 :     power = ceil(power);
     498                 :   }
     499                 : 
     500               0 :   return pow(kScaleResolution, power);
     501                 : }
     502                 : 
     503                 : 
     504                 : /*static*/ void
     505               0 : gfxUtils::PathFromRegion(gfxContext* aContext, const nsIntRegion& aRegion)
     506                 : {
     507               0 :   PathFromRegionInternal(aContext, aRegion, false);
     508               0 : }
     509                 : 
     510                 : /*static*/ void
     511               0 : gfxUtils::PathFromRegionSnapped(gfxContext* aContext, const nsIntRegion& aRegion)
     512                 : {
     513               0 :   PathFromRegionInternal(aContext, aRegion, true);
     514               0 : }
     515                 : 
     516                 : 
     517                 : bool
     518               0 : gfxUtils::GfxRectToIntRect(const gfxRect& aIn, nsIntRect* aOut)
     519                 : {
     520               0 :   *aOut = nsIntRect(PRInt32(aIn.X()), PRInt32(aIn.Y()),
     521               0 :   PRInt32(aIn.Width()), PRInt32(aIn.Height()));
     522               0 :   return gfxRect(aOut->x, aOut->y, aOut->width, aOut->height).IsEqualEdges(aIn);
     523                 : }
     524                 : 
     525                 : void
     526               0 : gfxUtils::GetYCbCrToRGBDestFormatAndSize(const PlanarYCbCrImage::Data& aData,
     527                 :                                          gfxASurface::gfxImageFormat& aSuggestedFormat,
     528                 :                                          gfxIntSize& aSuggestedSize)
     529                 : {
     530                 :   gfx::YUVType yuvtype =
     531                 :     gfx::TypeFromSize(aData.mYSize.width,
     532                 :                       aData.mYSize.height,
     533                 :                       aData.mCbCrSize.width,
     534               0 :                       aData.mCbCrSize.height);
     535                 : 
     536                 :   // 'prescale' is true if the scaling is to be done as part of the
     537                 :   // YCbCr to RGB conversion rather than on the RGB data when rendered.
     538                 :   bool prescale = aSuggestedSize.width > 0 && aSuggestedSize.height > 0 &&
     539               0 :                     aSuggestedSize != aData.mPicSize;
     540                 : 
     541               0 :   if (aSuggestedFormat == gfxASurface::ImageFormatRGB16_565) {
     542                 : #if defined(HAVE_YCBCR_TO_RGB565)
     543                 :     if (prescale &&
     544                 :         !gfx::IsScaleYCbCrToRGB565Fast(aData.mPicX,
     545                 :                                        aData.mPicY,
     546                 :                                        aData.mPicSize.width,
     547                 :                                        aData.mPicSize.height,
     548                 :                                        aSuggestedSize.width,
     549                 :                                        aSuggestedSize.height,
     550                 :                                        yuvtype,
     551                 :                                        gfx::FILTER_BILINEAR) &&
     552                 :         gfx::IsConvertYCbCrToRGB565Fast(aData.mPicX,
     553                 :                                         aData.mPicY,
     554                 :                                         aData.mPicSize.width,
     555                 :                                         aData.mPicSize.height,
     556                 :                                         yuvtype)) {
     557                 :       prescale = false;
     558                 :     }
     559                 : #else
     560                 :     // yuv2rgb16 function not available
     561               0 :     aSuggestedFormat = gfxASurface::ImageFormatRGB24;
     562                 : #endif
     563                 :   }
     564               0 :   else if (aSuggestedFormat != gfxASurface::ImageFormatRGB24) {
     565                 :     // No other formats are currently supported.
     566               0 :     aSuggestedFormat = gfxASurface::ImageFormatRGB24;
     567                 :   }
     568               0 :   if (aSuggestedFormat == gfxASurface::ImageFormatRGB24) {
     569                 :     /* ScaleYCbCrToRGB32 does not support a picture offset, nor 4:4:4 data.
     570                 :        See bugs 639415 and 640073. */
     571               0 :     if (aData.mPicX != 0 || aData.mPicY != 0 || yuvtype == gfx::YV24)
     572               0 :       prescale = false;
     573                 :   }
     574               0 :   if (!prescale) {
     575               0 :     aSuggestedSize = aData.mPicSize;
     576                 :   }
     577               0 : }
     578                 : 
     579                 : void
     580               0 : gfxUtils::ConvertYCbCrToRGB(const PlanarYCbCrImage::Data& aData,
     581                 :                             const gfxASurface::gfxImageFormat& aDestFormat,
     582                 :                             const gfxIntSize& aDestSize,
     583                 :                             unsigned char* aDestBuffer,
     584                 :                             PRInt32 aStride)
     585                 : {
     586                 :   gfx::YUVType yuvtype =
     587                 :     gfx::TypeFromSize(aData.mYSize.width,
     588                 :                       aData.mYSize.height,
     589                 :                       aData.mCbCrSize.width,
     590               0 :                       aData.mCbCrSize.height);
     591                 : 
     592                 :   // Convert from YCbCr to RGB now, scaling the image if needed.
     593               0 :   if (aDestSize != aData.mPicSize) {
     594                 : #if defined(HAVE_YCBCR_TO_RGB565)
     595                 :     if (aDestFormat == gfxASurface::ImageFormatRGB16_565) {
     596                 :       gfx::ScaleYCbCrToRGB565(aData.mYChannel,
     597                 :                               aData.mCbChannel,
     598                 :                               aData.mCrChannel,
     599                 :                               aDestBuffer,
     600                 :                               aData.mPicX,
     601                 :                               aData.mPicY,
     602                 :                               aData.mPicSize.width,
     603                 :                               aData.mPicSize.height,
     604                 :                               aDestSize.width,
     605                 :                               aDestSize.height,
     606                 :                               aData.mYStride,
     607                 :                               aData.mCbCrStride,
     608                 :                               aStride,
     609                 :                               yuvtype,
     610                 :                               gfx::FILTER_BILINEAR);
     611                 :     } else
     612                 : #endif
     613                 :       gfx::ScaleYCbCrToRGB32(aData.mYChannel,
     614                 :                              aData.mCbChannel,
     615                 :                              aData.mCrChannel,
     616                 :                              aDestBuffer,
     617                 :                              aData.mPicSize.width,
     618                 :                              aData.mPicSize.height,
     619                 :                              aDestSize.width,
     620                 :                              aDestSize.height,
     621                 :                              aData.mYStride,
     622                 :                              aData.mCbCrStride,
     623                 :                              aStride,
     624                 :                              yuvtype,
     625                 :                              gfx::ROTATE_0,
     626               0 :                              gfx::FILTER_BILINEAR);
     627                 :   } else { // no prescale
     628                 : #if defined(HAVE_YCBCR_TO_RGB565)
     629                 :     if (aDestFormat == gfxASurface::ImageFormatRGB16_565) {
     630                 :       gfx::ConvertYCbCrToRGB565(aData.mYChannel,
     631                 :                                 aData.mCbChannel,
     632                 :                                 aData.mCrChannel,
     633                 :                                 aDestBuffer,
     634                 :                                 aData.mPicX,
     635                 :                                 aData.mPicY,
     636                 :                                 aData.mPicSize.width,
     637                 :                                 aData.mPicSize.height,
     638                 :                                 aData.mYStride,
     639                 :                                 aData.mCbCrStride,
     640                 :                                 aStride,
     641                 :                                 yuvtype);
     642                 :     } else // aDestFormat != gfxASurface::ImageFormatRGB16_565
     643                 : #endif
     644                 :       gfx::ConvertYCbCrToRGB32(aData.mYChannel,
     645                 :                                aData.mCbChannel,
     646                 :                                aData.mCrChannel,
     647                 :                                aDestBuffer,
     648                 :                                aData.mPicX,
     649                 :                                aData.mPicY,
     650                 :                                aData.mPicSize.width,
     651                 :                                aData.mPicSize.height,
     652                 :                                aData.mYStride,
     653                 :                                aData.mCbCrStride,
     654                 :                                aStride,
     655               0 :                                yuvtype);
     656                 :   }
     657               0 : }
     658                 : 
     659                 : #ifdef MOZ_DUMP_PAINTING
     660                 : /* static */ void
     661               0 : gfxUtils::WriteAsPNG(DrawTarget* aDT, const char* aFile)
     662                 : {
     663               0 :   aDT->Flush();
     664               0 :   nsRefPtr<gfxASurface> surf = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(aDT);
     665               0 :   if (surf) {
     666               0 :     surf->WriteAsPNG(aFile);
     667                 :   } else {
     668               0 :     NS_WARNING("Failed to get Thebes surface!");
     669                 :   }
     670               0 : }
     671                 : 
     672                 : /* static */ void
     673               0 : gfxUtils::DumpAsDataURL(DrawTarget* aDT)
     674                 : {
     675               0 :   aDT->Flush();
     676               0 :   nsRefPtr<gfxASurface> surf = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(aDT);
     677               0 :   if (surf) {
     678               0 :     surf->DumpAsDataURL();
     679                 :   } else {
     680               0 :     NS_WARNING("Failed to get Thebes surface!");
     681                 :   }
     682               0 : }
     683                 : 
     684                 : /* static */ void
     685               0 : gfxUtils::CopyAsDataURL(DrawTarget* aDT)
     686                 : {
     687               0 :   aDT->Flush();
     688               0 :   nsRefPtr<gfxASurface> surf = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(aDT);
     689               0 :   if (surf) {
     690               0 :     surf->CopyAsDataURL();
     691                 :   } else {
     692               0 :     NS_WARNING("Failed to get Thebes surface!");
     693                 :   }
     694               0 : }
     695                 : 
     696            1464 : bool gfxUtils::sDumpPainting = getenv("MOZ_DUMP_PAINT_LIST") != 0;
     697            1464 : bool gfxUtils::sDumpPaintingToFile = getenv("MOZ_DUMP_PAINT_TO_FILE") != 0;
     698            4392 : FILE *gfxUtils::sDumpPaintFile = NULL;
     699                 : #endif

Generated by: LCOV version 1.7