gfx/src/nsRegion.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #ifndef nsRegion_h__
     7 #define nsRegion_h__
     9 #include <stddef.h>                     // for size_t
    10 #include <stdint.h>                     // for uint32_t, uint64_t
    11 #include <sys/types.h>                  // for int32_t
    12 #include "gfxCore.h"                    // for NS_GFX
    13 #include "nsCoord.h"                    // for nscoord
    14 #include "nsError.h"                    // for nsresult
    15 #include "nsPoint.h"                    // for nsIntPoint, nsPoint
    16 #include "nsRect.h"                     // for nsIntRect, nsRect
    17 #include "nsMargin.h"                   // for nsIntMargin
    18 #include "nsStringGlue.h"               // for nsCString
    19 #include "xpcom-config.h"               // for CPP_THROW_NEW
    21 class nsIntRegion;
    23 #include "pixman.h"
    25 /* For information on the internal representation look at pixman-region.c
    26  *
    27  * This replaces an older homebrew implementation of nsRegion. The
    28  * representation used here may use more rectangles than nsRegion however, the
    29  * representation is canonical.  This means that there's no need for an
    30  * Optimize() method because for a paticular region there is only one
    31  * representation. This means that nsIntRegion will have more predictable
    32  * performance characteristics than the old nsRegion and should not become
    33  * degenerate.
    34  *
    35  * The pixman region code originates from X11 which has spread to a variety of
    36  * projects including Qt, Gtk, Wine. It should perform reasonably well.
    37  */
    39 class nsRegionRectIterator;
    41 class nsRegion
    42 {
    44   friend class nsRegionRectIterator;
    46 public:
    47   nsRegion () { pixman_region32_init(&mImpl); }
    48   nsRegion (const nsRect& aRect) { pixman_region32_init_rect(&mImpl,
    49                                                                     aRect.x,
    50                                                                     aRect.y,
    51                                                                     aRect.width,
    52                                                                     aRect.height); }
    53   nsRegion (const nsRegion& aRegion) { pixman_region32_init(&mImpl); pixman_region32_copy(&mImpl,aRegion.Impl()); }
    54  ~nsRegion () { pixman_region32_fini(&mImpl); }
    55   nsRegion& operator = (const nsRect& aRect) { Copy (aRect); return *this; }
    56   nsRegion& operator = (const nsRegion& aRegion) { Copy (aRegion); return *this; }
    57   bool operator==(const nsRegion& aRgn) const
    58   {
    59     return IsEqual(aRgn);
    60   }
    62   void Swap(nsRegion* aOther)
    63   {
    64     pixman_region32_t tmp = mImpl;
    65     mImpl = aOther->mImpl;
    66     aOther->mImpl = tmp;
    67   }
    69   static
    70   nsresult InitStatic()
    71   {
    72     return NS_OK;
    73   }
    75   static
    76   void ShutdownStatic() {}
    78   nsRegion& And(const nsRegion& aRgn1,   const nsRegion& aRgn2)
    79   {
    80     pixman_region32_intersect(&mImpl, aRgn1.Impl(), aRgn2.Impl());
    81     return *this;
    82   }
    83   nsRegion& And(const nsRect& aRect, const nsRegion& aRegion)
    84   {
    85     return And(aRegion, aRect);
    86   }
    87   nsRegion& And(const nsRegion& aRegion, const nsRect& aRect)
    88   {
    89     pixman_region32_intersect_rect(&mImpl, aRegion.Impl(), aRect.x, aRect.y, aRect.width, aRect.height);
    90     return *this;
    91   }
    92   nsRegion& And(const nsRect& aRect1, const nsRect& aRect2)
    93   {
    94     nsRect TmpRect;
    96     TmpRect.IntersectRect(aRect1, aRect2);
    97     return Copy(TmpRect);
    98   }
   100   nsRegion& Or(const nsRegion& aRgn1, const nsRegion& aRgn2)
   101   {
   102     pixman_region32_union(&mImpl, aRgn1.Impl(), aRgn2.Impl());
   103     return *this;
   104   }
   105   nsRegion& Or(const nsRegion& aRegion, const nsRect& aRect)
   106   {
   107     pixman_region32_union_rect(&mImpl, aRegion.Impl(), aRect.x, aRect.y, aRect.width, aRect.height);
   108     return *this;
   109   }
   110   nsRegion& Or(const nsRect& aRect, const nsRegion& aRegion)
   111   {
   112     return  Or(aRegion, aRect);
   113   }
   114   nsRegion& Or(const nsRect& aRect1, const nsRect& aRect2)
   115   {
   116     Copy (aRect1);
   117     return Or (*this, aRect2);
   118   }
   120   nsRegion& Xor(const nsRegion& aRgn1,   const nsRegion& aRgn2)
   121   {
   122     // this could be implemented better if pixman had direct
   123     // support for xoring regions.
   124     nsRegion p;
   125     p.Sub(aRgn1, aRgn2);
   126     nsRegion q;
   127     q.Sub(aRgn2, aRgn1);
   128     return Or(p, q);
   129   }
   130   nsRegion& Xor(const nsRegion& aRegion, const nsRect& aRect)
   131   {
   132     return Xor(aRegion, nsRegion(aRect));
   133   }
   134   nsRegion& Xor(const nsRect& aRect, const nsRegion& aRegion)
   135   {
   136     return Xor(nsRegion(aRect), aRegion);
   137   }
   138   nsRegion& Xor(const nsRect& aRect1, const nsRect& aRect2)
   139   {
   140     return Xor(nsRegion(aRect1), nsRegion(aRect2));
   141   }
   143   nsRegion ToAppUnits (nscoord aAppUnitsPerPixel) const;
   144   nsRegion& Sub(const nsRegion& aRgn1, const nsRegion& aRgn2)
   145   {
   146     pixman_region32_subtract(&mImpl, aRgn1.Impl(), aRgn2.Impl());
   147     return *this;
   148   }
   149   nsRegion& Sub(const nsRegion& aRegion, const nsRect& aRect)
   150   {
   151     return Sub(aRegion, nsRegion(aRect));
   152   }
   153   nsRegion& Sub(const nsRect& aRect, const nsRegion& aRegion)
   154   {
   155     return Sub(nsRegion(aRect), aRegion);
   156   }
   157   nsRegion& Sub(const nsRect& aRect1, const nsRect& aRect2)
   158   {
   159     Copy(aRect1);
   160     return Sub(*this, aRect2);
   161   }
   163   bool Contains (const nsRect& aRect) const
   164   {
   165     pixman_box32_t box = RectToBox(aRect);
   166     return pixman_region32_contains_rectangle(Impl(), &box) == PIXMAN_REGION_IN;
   167   }
   168   bool Contains (const nsRegion& aRgn) const;
   169   bool Intersects (const nsRect& aRect) const;
   171   void MoveBy (int32_t aXOffset, int32_t aYOffset)
   172   {
   173     MoveBy (nsPoint (aXOffset, aYOffset));
   174   }
   175   void MoveBy (nsPoint aPt) { pixman_region32_translate(&mImpl, aPt.x, aPt.y); }
   176   void SetEmpty ()
   177   {
   178     pixman_region32_clear(&mImpl);
   179   }
   181   nsRegion MovedBy(int32_t aXOffset, int32_t aYOffset) const
   182   {
   183     return MovedBy(nsPoint(aXOffset, aYOffset));
   184   }
   185   nsRegion MovedBy(const nsPoint& aPt) const
   186   {
   187     nsRegion copy(*this);
   188     copy.MoveBy(aPt);
   189     return copy;
   190   }
   192   nsRegion Intersect(const nsRegion& aOther) const
   193   {
   194     nsRegion intersection;
   195     intersection.And(*this, aOther);
   196     return intersection;
   197   }
   199   void Inflate(const nsMargin& aMargin);
   201   nsRegion Inflated(const nsMargin& aMargin) const
   202   {
   203     nsRegion copy(*this);
   204     copy.Inflate(aMargin);
   205     return copy;
   206   }
   208   bool IsEmpty () const { return !pixman_region32_not_empty(Impl()); }
   209   bool IsComplex () const { return GetNumRects() > 1; }
   210   bool IsEqual (const nsRegion& aRegion) const
   211   {
   212     return pixman_region32_equal(Impl(), aRegion.Impl());
   213   }
   214   uint32_t GetNumRects () const { return pixman_region32_n_rects(Impl()); }
   215   const nsRect GetBounds () const { return BoxToRect(mImpl.extents); }
   216   uint64_t Area () const;
   217   // Converts this region from aFromAPP, an appunits per pixel ratio, to
   218   // aToAPP. This applies nsRect::ConvertAppUnitsRoundOut/In to each rect of
   219   // the region.
   220   nsRegion ConvertAppUnitsRoundOut (int32_t aFromAPP, int32_t aToAPP) const;
   221   nsRegion ConvertAppUnitsRoundIn (int32_t aFromAPP, int32_t aToAPP) const;
   222   nsRegion& ScaleRoundOut(float aXScale, float aYScale);
   223   nsRegion& ScaleInverseRoundOut(float aXScale, float aYScale);
   224   nsIntRegion ScaleToOutsidePixels (float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
   225   nsIntRegion ScaleToInsidePixels (float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
   226   nsIntRegion ScaleToNearestPixels (float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
   227   nsIntRegion ToOutsidePixels (nscoord aAppUnitsPerPixel) const;
   228   nsIntRegion ToNearestPixels (nscoord aAppUnitsPerPixel) const;
   230   /**
   231    * Gets the largest rectangle contained in the region.
   232    * @param aContainingRect if non-empty, we choose a rectangle that
   233    * maximizes the area intersecting with aContainingRect (and break ties by
   234    * then choosing the largest rectangle overall)
   235    */
   236   nsRect GetLargestRectangle (const nsRect& aContainingRect = nsRect()) const;
   238   /**
   239    * Make sure the region has at most aMaxRects by adding area to it
   240    * if necessary. The simplified region will be a superset of the
   241    * original region. The simplified region's bounding box will be
   242    * the same as for the current region.
   243    */
   244   void SimplifyOutward (uint32_t aMaxRects);
   245   /**
   246    * Simplify the region by adding at most aThreshold area between spans of
   247    * rects.  The simplified region will be a superset of the original region.
   248    * The simplified region's bounding box will be the same as for the current
   249    * region.
   250    */
   251   void SimplifyOutwardByArea(uint32_t aThreshold);
   252   /**
   253    * Make sure the region has at most aMaxRects by removing area from
   254    * it if necessary. The simplified region will be a subset of the
   255    * original region.
   256    */
   257   void SimplifyInward (uint32_t aMaxRects);
   259   nsCString ToString() const;
   260 private:
   261   pixman_region32_t mImpl;
   263   nsIntRegion ToPixels(nscoord aAppUnitsPerPixel, bool aOutsidePixels) const;
   265   nsRegion& Copy (const nsRegion& aRegion)
   266   {
   267     pixman_region32_copy(&mImpl, aRegion.Impl());
   268     return *this;
   269   }
   271   nsRegion& Copy (const nsRect& aRect)
   272   {
   273     // pixman needs to distinguish between an empty region and a region
   274     // with one rect so that it can return a different number of rectangles.
   275     // Empty rect: data = empty_box
   276     //     1 rect: data = null
   277     //    >1 rect: data = rects
   278     if (aRect.IsEmpty()) {
   279       pixman_region32_clear(&mImpl);
   280     } else {
   281       pixman_box32_t box = RectToBox(aRect);
   282       pixman_region32_reset(&mImpl, &box);
   283     }
   284     return *this;
   285   }
   287   static inline pixman_box32_t RectToBox(const nsRect &aRect)
   288   {
   289     pixman_box32_t box = { aRect.x, aRect.y, aRect.XMost(), aRect.YMost() };
   290     return box;
   291   }
   293   static inline pixman_box32_t RectToBox(const nsIntRect &aRect)
   294   {
   295     pixman_box32_t box = { aRect.x, aRect.y, aRect.XMost(), aRect.YMost() };
   296     return box;
   297   }
   300   static inline nsRect BoxToRect(const pixman_box32_t &aBox)
   301   {
   302     return nsRect(aBox.x1, aBox.y1,
   303                   aBox.x2 - aBox.x1,
   304                   aBox.y2 - aBox.y1);
   305   }
   307   pixman_region32_t* Impl() const
   308   {
   309     return const_cast<pixman_region32_t*>(&mImpl);
   310   }
   312 };
   315 class NS_GFX nsRegionRectIterator
   316 {
   317   const nsRegion*  mRegion;
   318   int i;
   319   int n;
   320   nsRect rect;
   321   pixman_box32_t *boxes;
   323 public:
   324   nsRegionRectIterator (const nsRegion& aRegion)
   325   {
   326     mRegion = &aRegion;
   327     i = 0;
   328     boxes = pixman_region32_rectangles(aRegion.Impl(), &n);
   329   }
   331   const nsRect* Next ()
   332   {
   333     if (i == n)
   334       return nullptr;
   335     rect = nsRegion::BoxToRect(boxes[i]);
   336     i++;
   337     return &rect;
   338   }
   340   const nsRect* Prev ()
   341   {
   342     if (i == -1)
   343       return nullptr;
   344     rect = nsRegion::BoxToRect(boxes[i]);
   345     i--;
   346     return &rect;
   347   }
   349   void Reset ()
   350   {
   351     i = 0;
   352   }
   353 };
   355 /**
   356  * nsIntRegions use int32_t coordinates and nsIntRects.
   357  */
   358 class NS_GFX nsIntRegion
   359 {
   360   friend class nsIntRegionRectIterator;
   361   friend class nsRegion;
   363 public:
   364   nsIntRegion () {}
   365   nsIntRegion (const nsIntRect& aRect) : mImpl (ToRect(aRect)) {}
   366   nsIntRegion (const nsIntRegion& aRegion) : mImpl (aRegion.mImpl) {}
   367   nsIntRegion& operator = (const nsIntRect& aRect) { mImpl = ToRect (aRect); return *this; }
   368   nsIntRegion& operator = (const nsIntRegion& aRegion) { mImpl = aRegion.mImpl; return *this; }
   370   bool operator==(const nsIntRegion& aRgn) const
   371   {
   372     return IsEqual(aRgn);
   373   }
   375   void Swap(nsIntRegion* aOther)
   376   {
   377     mImpl.Swap(&aOther->mImpl);
   378   }
   380   nsIntRegion& And  (const nsIntRegion& aRgn1,   const nsIntRegion& aRgn2)
   381   {
   382     mImpl.And (aRgn1.mImpl, aRgn2.mImpl);
   383     return *this;
   384   }
   385   nsIntRegion& And  (const nsIntRegion& aRegion, const nsIntRect& aRect)
   386   {
   387     mImpl.And (aRegion.mImpl, ToRect (aRect));
   388     return *this;
   389   }
   390   nsIntRegion& And  (const nsIntRect& aRect, const nsIntRegion& aRegion)
   391   {
   392     return  And  (aRegion, aRect);
   393   }
   394   nsIntRegion& And  (const nsIntRect& aRect1, const nsIntRect& aRect2)
   395   {
   396     nsIntRect TmpRect;
   398     TmpRect.IntersectRect (aRect1, aRect2);
   399     mImpl = ToRect (TmpRect);
   400     return *this;
   401   }
   403   nsIntRegion& Or   (const nsIntRegion& aRgn1,   const nsIntRegion& aRgn2)
   404   {
   405     mImpl.Or (aRgn1.mImpl, aRgn2.mImpl);
   406     return *this;
   407   }
   408   nsIntRegion& Or   (const nsIntRegion& aRegion, const nsIntRect& aRect)
   409   {
   410     mImpl.Or (aRegion.mImpl, ToRect (aRect));
   411     return *this;
   412   }
   413   nsIntRegion& Or   (const nsIntRect& aRect, const nsIntRegion& aRegion)
   414   {
   415     return  Or   (aRegion, aRect);
   416   }
   417   nsIntRegion& Or   (const nsIntRect& aRect1, const nsIntRect& aRect2)
   418   {
   419     mImpl = ToRect (aRect1);
   420     return Or (*this, aRect2);
   421   }
   423   nsIntRegion& Xor  (const nsIntRegion& aRgn1,   const nsIntRegion& aRgn2)
   424   {
   425     mImpl.Xor (aRgn1.mImpl, aRgn2.mImpl);
   426     return *this;
   427   }
   428   nsIntRegion& Xor  (const nsIntRegion& aRegion, const nsIntRect& aRect)
   429   {
   430     mImpl.Xor (aRegion.mImpl, ToRect (aRect));
   431     return *this;
   432   }
   433   nsIntRegion& Xor  (const nsIntRect& aRect, const nsIntRegion& aRegion)
   434   {
   435     return  Xor  (aRegion, aRect);
   436   }
   437   nsIntRegion& Xor  (const nsIntRect& aRect1, const nsIntRect& aRect2)
   438   {
   439     mImpl = ToRect (aRect1);
   440     return Xor (*this, aRect2);
   441   }
   443   nsIntRegion& Sub  (const nsIntRegion& aRgn1,   const nsIntRegion& aRgn2)
   444   {
   445     mImpl.Sub (aRgn1.mImpl, aRgn2.mImpl);
   446     return *this;
   447   }
   448   nsIntRegion& Sub  (const nsIntRegion& aRegion, const nsIntRect& aRect)
   449   {
   450     mImpl.Sub (aRegion.mImpl, ToRect (aRect));
   451     return *this;
   452   }
   453   nsIntRegion& Sub  (const nsIntRect& aRect, const nsIntRegion& aRegion)
   454   {
   455     return Sub (nsIntRegion (aRect), aRegion);
   456   }
   457   nsIntRegion& Sub  (const nsIntRect& aRect1, const nsIntRect& aRect2)
   458   {
   459     mImpl = ToRect (aRect1);
   460     return Sub (*this, aRect2);
   461   }
   463   bool Contains (const nsIntRect& aRect) const
   464   {
   465     return mImpl.Contains (ToRect (aRect));
   466   }
   467   bool Contains (const nsIntRegion& aRgn) const
   468   {
   469     return mImpl.Contains (aRgn.mImpl);
   470   }
   471   bool Intersects (const nsIntRect& aRect) const
   472   {
   473     return mImpl.Intersects (ToRect (aRect));
   474   }
   476   void MoveBy (int32_t aXOffset, int32_t aYOffset)
   477   {
   478     MoveBy (nsIntPoint (aXOffset, aYOffset));
   479   }
   480   void MoveBy (nsIntPoint aPt)
   481   {
   482     mImpl.MoveBy (aPt.x, aPt.y);
   483   }
   484   nsIntRegion MovedBy(int32_t aXOffset, int32_t aYOffset) const
   485   {
   486     return MovedBy(nsIntPoint(aXOffset, aYOffset));
   487   }
   488   nsIntRegion MovedBy(const nsIntPoint& aPt) const
   489   {
   490     nsIntRegion copy(*this);
   491     copy.MoveBy(aPt);
   492     return copy;
   493   }
   495   nsIntRegion Intersect(const nsIntRegion& aOther) const
   496   {
   497     nsIntRegion intersection;
   498     intersection.And(*this, aOther);
   499     return intersection;
   500   }
   502   void Inflate(const nsIntMargin& aMargin)
   503   {
   504     mImpl.Inflate(nsMargin(aMargin.top, aMargin.right, aMargin.bottom, aMargin.left));
   505   }
   506   nsIntRegion Inflated(const nsIntMargin& aMargin) const
   507   {
   508     nsIntRegion copy(*this);
   509     copy.Inflate(aMargin);
   510     return copy;
   511   }
   513   void SetEmpty ()
   514   {
   515     mImpl.SetEmpty  ();
   516   }
   518   bool IsEmpty () const { return mImpl.IsEmpty (); }
   519   bool IsComplex () const { return mImpl.IsComplex (); }
   520   bool IsEqual (const nsIntRegion& aRegion) const
   521   {
   522     return mImpl.IsEqual (aRegion.mImpl);
   523   }
   524   uint32_t GetNumRects () const { return mImpl.GetNumRects (); }
   525   nsIntRect GetBounds () const { return FromRect (mImpl.GetBounds ()); }
   526   uint64_t Area () const { return mImpl.Area(); }
   527   nsRegion ToAppUnits (nscoord aAppUnitsPerPixel) const;
   528   nsIntRect GetLargestRectangle (const nsIntRect& aContainingRect = nsIntRect()) const
   529   {
   530     return FromRect (mImpl.GetLargestRectangle( ToRect(aContainingRect) ));
   531   }
   533   nsIntRegion& ScaleRoundOut (float aXScale, float aYScale)
   534   {
   535     mImpl.ScaleRoundOut(aXScale, aYScale);
   536     return *this;
   537   }
   539   /**
   540    * Make sure the region has at most aMaxRects by adding area to it
   541    * if necessary. The simplified region will be a superset of the
   542    * original region. The simplified region's bounding box will be
   543    * the same as for the current region.
   544    */
   545   void SimplifyOutward (uint32_t aMaxRects)
   546   {
   547     mImpl.SimplifyOutward (aMaxRects);
   548   }
   549   void SimplifyOutwardByArea (uint32_t aThreshold)
   550   {
   551     mImpl.SimplifyOutwardByArea (aThreshold);
   552   }
   553   /**
   554    * Make sure the region has at most aMaxRects by removing area from
   555    * it if necessary. The simplified region will be a subset of the
   556    * original region.
   557    */
   558   void SimplifyInward (uint32_t aMaxRects)
   559   {
   560     mImpl.SimplifyInward (aMaxRects);
   561   }
   563   nsCString ToString() const { return mImpl.ToString(); }
   565 private:
   566   nsRegion mImpl;
   568   static nsRect ToRect(const nsIntRect& aRect)
   569   {
   570     return nsRect (aRect.x, aRect.y, aRect.width, aRect.height);
   571   }
   572   static nsIntRect FromRect(const nsRect& aRect)
   573   {
   574     return nsIntRect (aRect.x, aRect.y, aRect.width, aRect.height);
   575   }
   576 };
   578 class NS_GFX nsIntRegionRectIterator
   579 {
   580   nsRegionRectIterator mImpl;
   581   nsIntRect mTmp;
   583 public:
   584   nsIntRegionRectIterator (const nsIntRegion& aRegion) : mImpl (aRegion.mImpl) {}
   586   const nsIntRect* Next ()
   587   {
   588     const nsRect* r = mImpl.Next();
   589     if (!r)
   590       return nullptr;
   591     mTmp = nsIntRegion::FromRect (*r);
   592     return &mTmp;
   593   }
   595   const nsIntRect* Prev ()
   596   {
   597     const nsRect* r = mImpl.Prev();
   598     if (!r)
   599       return nullptr;
   600     mTmp = nsIntRegion::FromRect (*r);
   601     return &mTmp;
   602   }
   604   void Reset ()
   605   {
   606     mImpl.Reset ();
   607   }
   608 };
   609 #endif

mercurial