layout/base/DisplayItemClip.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "DisplayItemClip.h"
     8 #include "gfxContext.h"
     9 #include "nsPresContext.h"
    10 #include "nsCSSRendering.h"
    11 #include "nsLayoutUtils.h"
    12 #include "nsRegion.h"
    14 namespace mozilla {
    16 void
    17 DisplayItemClip::SetTo(const nsRect& aRect)
    18 {
    19   mHaveClipRect = true;
    20   mClipRect = aRect;
    21   mRoundedClipRects.Clear();
    22 }
    24 void
    25 DisplayItemClip::SetTo(const nsRect& aRect, const nscoord* aRadii)
    26 {
    27   mHaveClipRect = true;
    28   mClipRect = aRect;
    29   mRoundedClipRects.SetLength(1);
    30   mRoundedClipRects[0].mRect = aRect;
    31   memcpy(mRoundedClipRects[0].mRadii, aRadii, sizeof(nscoord)*8);
    32 }
    34 bool
    35 DisplayItemClip::MayIntersect(const nsRect& aRect) const
    36 {
    37   if (!mHaveClipRect) {
    38     return !aRect.IsEmpty();
    39   }
    40   nsRect r = aRect.Intersect(mClipRect);
    41   if (r.IsEmpty()) {
    42     return false;
    43   }
    44   for (uint32_t i = 0; i < mRoundedClipRects.Length(); ++i) {
    45     const RoundedRect& rr = mRoundedClipRects[i];
    46     if (!nsLayoutUtils::RoundedRectIntersectsRect(rr.mRect, rr.mRadii, r)) {
    47       return false;
    48     }
    49   }
    50   return true;
    51 }
    53 void
    54 DisplayItemClip::IntersectWith(const DisplayItemClip& aOther)
    55 {
    56   if (!aOther.mHaveClipRect) {
    57     return;
    58   }
    59   if (!mHaveClipRect) {
    60     *this = aOther;
    61     return;
    62   }
    63   if (!mClipRect.IntersectRect(mClipRect, aOther.mClipRect)) {
    64     mRoundedClipRects.Clear();
    65     return;
    66   }
    67   mRoundedClipRects.AppendElements(aOther.mRoundedClipRects);
    68 }
    70 void
    71 DisplayItemClip::ApplyTo(gfxContext* aContext,
    72                          nsPresContext* aPresContext,
    73                          uint32_t aBegin, uint32_t aEnd)
    74 {
    75   int32_t A2D = aPresContext->AppUnitsPerDevPixel();
    76   ApplyRectTo(aContext, A2D);
    77   ApplyRoundedRectsTo(aContext, A2D, aBegin, aEnd);
    78 }
    80 void
    81 DisplayItemClip::ApplyRectTo(gfxContext* aContext, int32_t A2D) const
    82 {
    83   aContext->NewPath();
    84   gfxRect clip = nsLayoutUtils::RectToGfxRect(mClipRect, A2D);
    85   aContext->Rectangle(clip, true);
    86   aContext->Clip();
    87 }
    89 void
    90 DisplayItemClip::ApplyRoundedRectsTo(gfxContext* aContext,
    91                                      int32_t A2D,
    92                                      uint32_t aBegin, uint32_t aEnd) const
    93 {
    94   aEnd = std::min<uint32_t>(aEnd, mRoundedClipRects.Length());
    96   for (uint32_t i = aBegin; i < aEnd; ++i) {
    97     AddRoundedRectPathTo(aContext, A2D, mRoundedClipRects[i]);
    98     aContext->Clip();
    99   }
   100 }
   102 void
   103 DisplayItemClip::DrawRoundedRectsTo(gfxContext* aContext,
   104                                     int32_t A2D,
   105                                     uint32_t aBegin, uint32_t aEnd) const
   106 {
   107   aEnd = std::min<uint32_t>(aEnd, mRoundedClipRects.Length());
   109   if (aEnd - aBegin == 0)
   110     return;
   112   // If there is just one rounded rect we can just fill it, if there are more then we
   113   // must clip the rest to get the intersection of clips
   114   ApplyRoundedRectsTo(aContext, A2D, aBegin, aEnd - 1);
   115   AddRoundedRectPathTo(aContext, A2D, mRoundedClipRects[aEnd - 1]);
   116   aContext->Fill();
   117 }
   119 void
   120 DisplayItemClip::AddRoundedRectPathTo(gfxContext* aContext,
   121                                       int32_t A2D,
   122                                       const RoundedRect &aRoundRect) const
   123 {
   124   gfxCornerSizes pixelRadii;
   125   nsCSSRendering::ComputePixelRadii(aRoundRect.mRadii, A2D, &pixelRadii);
   127   gfxRect clip = nsLayoutUtils::RectToGfxRect(aRoundRect.mRect, A2D);
   128   clip.Round();
   129   clip.Condition();
   131   aContext->NewPath();
   132   aContext->RoundedRectangle(clip, pixelRadii);
   133 }
   135 nsRect
   136 DisplayItemClip::ApproximateIntersectInward(const nsRect& aRect) const
   137 {
   138   nsRect r = aRect;
   139   if (mHaveClipRect) {
   140     r.IntersectRect(r, mClipRect);
   141   }
   142   for (uint32_t i = 0, iEnd = mRoundedClipRects.Length();
   143        i < iEnd; ++i) {
   144     const RoundedRect &rr = mRoundedClipRects[i];
   145     nsRegion rgn = nsLayoutUtils::RoundedRectIntersectRect(rr.mRect, rr.mRadii, r);
   146     r = rgn.GetLargestRectangle();
   147   }
   148   return r;
   149 }
   151 // Test if (aXPoint, aYPoint) is in the ellipse with center (aXCenter, aYCenter)
   152 // and radii aXRadius, aYRadius.
   153 bool IsInsideEllipse(nscoord aXRadius, nscoord aXCenter, nscoord aXPoint,
   154                      nscoord aYRadius, nscoord aYCenter, nscoord aYPoint)
   155 {
   156   float scaledX = float(aXPoint - aXCenter) / float(aXRadius);
   157   float scaledY = float(aYPoint - aYCenter) / float(aYRadius);
   158   return scaledX * scaledX + scaledY * scaledY < 1.0f;
   159 }
   161 bool
   162 DisplayItemClip::IsRectClippedByRoundedCorner(const nsRect& aRect) const
   163 {
   164   if (mRoundedClipRects.IsEmpty())
   165     return false;
   167   nsRect rect;
   168   rect.IntersectRect(aRect, NonRoundedIntersection());
   169   for (uint32_t i = 0, iEnd = mRoundedClipRects.Length();
   170        i < iEnd; ++i) {
   171     const RoundedRect &rr = mRoundedClipRects[i];
   172     // top left
   173     if (rect.x < rr.mRect.x + rr.mRadii[NS_CORNER_TOP_LEFT_X] &&
   174         rect.y < rr.mRect.y + rr.mRadii[NS_CORNER_TOP_LEFT_Y]) {
   175       if (!IsInsideEllipse(rr.mRadii[NS_CORNER_TOP_LEFT_X],
   176                            rr.mRect.x + rr.mRadii[NS_CORNER_TOP_LEFT_X],
   177                            rect.x,
   178                            rr.mRadii[NS_CORNER_TOP_LEFT_Y],
   179                            rr.mRect.y + rr.mRadii[NS_CORNER_TOP_LEFT_Y],
   180                            rect.y)) {
   181         return true;
   182       }
   183     }
   184     // top right
   185     if (rect.XMost() > rr.mRect.XMost() - rr.mRadii[NS_CORNER_TOP_RIGHT_X] &&
   186         rect.y < rr.mRect.y + rr.mRadii[NS_CORNER_TOP_RIGHT_Y]) {
   187       if (!IsInsideEllipse(rr.mRadii[NS_CORNER_TOP_RIGHT_X],
   188                            rr.mRect.XMost() - rr.mRadii[NS_CORNER_TOP_RIGHT_X],
   189                            rect.XMost(),
   190                            rr.mRadii[NS_CORNER_TOP_RIGHT_Y],
   191                            rr.mRect.y + rr.mRadii[NS_CORNER_TOP_RIGHT_Y],
   192                            rect.y)) {
   193         return true;
   194       }
   195     }
   196     // bottom left
   197     if (rect.x < rr.mRect.x + rr.mRadii[NS_CORNER_BOTTOM_LEFT_X] &&
   198         rect.YMost() > rr.mRect.YMost() - rr.mRadii[NS_CORNER_BOTTOM_LEFT_Y]) {
   199       if (!IsInsideEllipse(rr.mRadii[NS_CORNER_BOTTOM_LEFT_X],
   200                            rr.mRect.x + rr.mRadii[NS_CORNER_BOTTOM_LEFT_X],
   201                            rect.x,
   202                            rr.mRadii[NS_CORNER_BOTTOM_LEFT_Y],
   203                            rr.mRect.YMost() - rr.mRadii[NS_CORNER_BOTTOM_LEFT_Y],
   204                            rect.YMost())) {
   205         return true;
   206       }
   207     }
   208     // bottom right
   209     if (rect.XMost() > rr.mRect.XMost() - rr.mRadii[NS_CORNER_BOTTOM_RIGHT_X] &&
   210         rect.YMost() > rr.mRect.YMost() - rr.mRadii[NS_CORNER_BOTTOM_RIGHT_Y]) {
   211       if (!IsInsideEllipse(rr.mRadii[NS_CORNER_BOTTOM_RIGHT_X],
   212                            rr.mRect.XMost() - rr.mRadii[NS_CORNER_BOTTOM_RIGHT_X],
   213                            rect.XMost(),
   214                            rr.mRadii[NS_CORNER_BOTTOM_RIGHT_Y],
   215                            rr.mRect.YMost() - rr.mRadii[NS_CORNER_BOTTOM_RIGHT_Y],
   216                            rect.YMost())) {
   217         return true;
   218       }
   219     }
   220   }
   221   return false;
   222 }
   224 nsRect
   225 DisplayItemClip::NonRoundedIntersection() const
   226 {
   227   NS_ASSERTION(mHaveClipRect, "Must have a clip rect!");
   228   nsRect result = mClipRect;
   229   for (uint32_t i = 0, iEnd = mRoundedClipRects.Length();
   230        i < iEnd; ++i) {
   231     result.IntersectRect(result, mRoundedClipRects[i].mRect);
   232   }
   233   return result;
   234 }
   236 bool
   237 DisplayItemClip::IsRectAffectedByClip(const nsRect& aRect) const
   238 {
   239   if (mHaveClipRect && !mClipRect.Contains(aRect)) {
   240     return true;
   241   }
   242   for (uint32_t i = 0, iEnd = mRoundedClipRects.Length();
   243        i < iEnd; ++i) {
   244     const RoundedRect &rr = mRoundedClipRects[i];
   245     nsRegion rgn = nsLayoutUtils::RoundedRectIntersectRect(rr.mRect, rr.mRadii, aRect);
   246     if (!rgn.Contains(aRect)) {
   247       return true;
   248     }
   249   }
   250   return false;
   251 }
   253 nsRect
   254 DisplayItemClip::ApplyNonRoundedIntersection(const nsRect& aRect) const
   255 {
   256   if (!mHaveClipRect) {
   257     return aRect;
   258   }
   260   nsRect result = aRect.Intersect(mClipRect);
   261   for (uint32_t i = 0, iEnd = mRoundedClipRects.Length();
   262        i < iEnd; ++i) {
   263     result.Intersect(mRoundedClipRects[i].mRect);
   264   }
   265   return result;
   266 }
   268 void
   269 DisplayItemClip::RemoveRoundedCorners()
   270 {
   271   if (mRoundedClipRects.IsEmpty())
   272     return;
   274   mClipRect = NonRoundedIntersection();
   275   mRoundedClipRects.Clear();
   276 }
   278 static void
   279 AccumulateRectDifference(const nsRect& aR1, const nsRect& aR2, nsRegion* aOut)
   280 {
   281   if (aR1.IsEqualInterior(aR2))
   282     return;
   283   nsRegion r;
   284   r.Xor(aR1, aR2);
   285   aOut->Or(*aOut, r);
   286 }
   288 void
   289 DisplayItemClip::AddOffsetAndComputeDifference(const nsPoint& aOffset,
   290                                                const nsRect& aBounds,
   291                                                const DisplayItemClip& aOther,
   292                                                const nsRect& aOtherBounds,
   293                                                nsRegion* aDifference)
   294 {
   295   if (mHaveClipRect != aOther.mHaveClipRect ||
   296       mRoundedClipRects.Length() != aOther.mRoundedClipRects.Length()) {
   297     aDifference->Or(*aDifference, aBounds);
   298     aDifference->Or(*aDifference, aOtherBounds);
   299     return;
   300   }
   301   if (mHaveClipRect) {
   302     AccumulateRectDifference((mClipRect + aOffset).Intersect(aBounds),
   303                              aOther.mClipRect.Intersect(aOtherBounds),
   304                              aDifference);
   305   }
   306   for (uint32_t i = 0; i < mRoundedClipRects.Length(); ++i) {
   307     if (mRoundedClipRects[i] + aOffset != aOther.mRoundedClipRects[i]) {
   308       // The corners make it tricky so we'll just add both rects here.
   309       aDifference->Or(*aDifference, mRoundedClipRects[i].mRect.Intersect(aBounds));
   310       aDifference->Or(*aDifference, aOther.mRoundedClipRects[i].mRect.Intersect(aOtherBounds));
   311     }
   312   }
   313 }
   315 uint32_t
   316 DisplayItemClip::GetCommonRoundedRectCount(const DisplayItemClip& aOther,
   317                                            uint32_t aMax) const
   318 {
   319   uint32_t end = std::min(std::min(mRoundedClipRects.Length(), aMax),
   320                           aOther.mRoundedClipRects.Length());
   321   uint32_t clipCount = 0;
   322   for (; clipCount < end; ++clipCount) {
   323     if (mRoundedClipRects[clipCount] !=
   324         aOther.mRoundedClipRects[clipCount]) {
   325       return clipCount;
   326     }
   327   }
   328   return clipCount;
   329 }
   331 void
   332 DisplayItemClip::AppendRoundedRects(nsTArray<RoundedRect>* aArray, uint32_t aCount) const
   333 {
   334   uint32_t count = std::min(mRoundedClipRects.Length(), aCount);
   335   for (uint32_t i = 0; i < count; ++i) {
   336     *aArray->AppendElement() = mRoundedClipRects[i];
   337   }
   338 }
   340 bool
   341 DisplayItemClip::ComputeRegionInClips(DisplayItemClip* aOldClip,
   342                                       const nsPoint& aShift,
   343                                       nsRegion* aCombined) const
   344 {
   345   if (!mHaveClipRect || (aOldClip && !aOldClip->mHaveClipRect)) {
   346     return false;
   347   }
   349   if (aOldClip) {
   350     *aCombined = aOldClip->NonRoundedIntersection();
   351     aCombined->MoveBy(aShift);
   352     aCombined->Or(*aCombined, NonRoundedIntersection());
   353   } else {
   354     *aCombined = NonRoundedIntersection();
   355   }
   356   return true;
   357 }
   359 void
   360 DisplayItemClip::MoveBy(nsPoint aPoint)
   361 {
   362   if (!mHaveClipRect)
   363     return;
   364   mClipRect += aPoint;
   365   for (uint32_t i = 0; i < mRoundedClipRects.Length(); ++i) {
   366     mRoundedClipRects[i].mRect += aPoint;
   367   }
   368 }
   370 static DisplayItemClip* gNoClip;
   372 const DisplayItemClip&
   373 DisplayItemClip::NoClip()
   374 {
   375   if (!gNoClip) {
   376     gNoClip = new DisplayItemClip();
   377   }
   378   return *gNoClip;
   379 }
   381 void
   382 DisplayItemClip::Shutdown()
   383 {
   384   delete gNoClip;
   385   gNoClip = nullptr;
   386 }
   388 #ifdef MOZ_DUMP_PAINTING
   389 nsCString
   390 DisplayItemClip::ToString() const
   391 {
   392   nsAutoCString str;
   393   if (mHaveClipRect) {
   394     str.AppendPrintf("%d,%d,%d,%d", mClipRect.x, mClipRect.y,
   395                      mClipRect.width, mClipRect.height);
   396     for (uint32_t i = 0; i < mRoundedClipRects.Length(); ++i) {
   397       const RoundedRect& r = mRoundedClipRects[i];
   398       str.AppendPrintf(" [%d,%d,%d,%d corners %d,%d,%d,%d,%d,%d,%d,%d]",
   399                        r.mRect.x, r.mRect.y, r.mRect.width, r.mRect.height,
   400                        r.mRadii[0], r.mRadii[1], r.mRadii[2], r.mRadii[3],
   401                        r.mRadii[4], r.mRadii[5], r.mRadii[6], r.mRadii[7]);
   402     }
   403   }
   404   return str;
   405 }
   406 #endif
   408 }

mercurial