LCOV - code coverage report
Current view: top level - gfx/src - nsRegion.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 224 528 42.4 %
Date: 2017-07-14 16:53:18 Functions: 28 45 62.2 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       4             : 
       5             : 
       6             : #include "nsRegion.h"
       7             : #include "nsTArray.h"
       8             : #include "gfxUtils.h"
       9             : #include "mozilla/ToString.h"
      10             : 
      11        1952 : bool nsRegion::Contains(const nsRegion& aRgn) const
      12             : {
      13             :   // XXX this could be made faster by iterating over
      14             :   // both regions at the same time some how
      15        2233 :   for (auto iter = aRgn.RectIter(); !iter.Done(); iter.Next()) {
      16         495 :     if (!Contains(iter.Get())) {
      17         214 :       return false;
      18             :     }
      19             :   }
      20        1738 :   return true;
      21             : }
      22             : 
      23        1864 : bool nsRegion::Intersects(const nsRect& aRect) const
      24             : {
      25             :   // XXX this could be made faster by using pixman_region32_contains_rect
      26        3182 :   for (auto iter = RectIter(); !iter.Done(); iter.Next()) {
      27        1471 :     if (iter.Get().Intersects(aRect)) {
      28         153 :       return true;
      29             :     }
      30             :   }
      31        1711 :   return false;
      32             : }
      33             : 
      34           0 : void nsRegion::Inflate(const nsMargin& aMargin)
      35             : {
      36             :   int n;
      37           0 :   pixman_box32_t *boxes = pixman_region32_rectangles(&mImpl, &n);
      38           0 :   for (int i=0; i<n; i++) {
      39           0 :     nsRect rect = BoxToRect(boxes[i]);
      40           0 :     rect.Inflate(aMargin);
      41           0 :     boxes[i] = RectToBox(rect);
      42             :   }
      43             : 
      44             :   pixman_region32_t region;
      45             :   // This will union all of the rectangles and runs in about O(n lg(n))
      46           0 :   pixman_region32_init_rects(&region, boxes, n);
      47             : 
      48           0 :   pixman_region32_fini(&mImpl);
      49           0 :   mImpl = region;
      50           0 : }
      51             : 
      52        3065 : void nsRegion::SimplifyOutward (uint32_t aMaxRects)
      53             : {
      54        3065 :   MOZ_ASSERT(aMaxRects >= 1, "Invalid max rect count");
      55             : 
      56        3065 :   if (GetNumRects() <= aMaxRects)
      57        3006 :     return;
      58             : 
      59             :   pixman_box32_t *boxes;
      60             :   int n;
      61          59 :   boxes = pixman_region32_rectangles(&mImpl, &n);
      62             : 
      63             :   // Try combining rects in horizontal bands into a single rect
      64          59 :   int dest = 0;
      65         288 :   for (int src = 1; src < n; src++)
      66             :   {
      67             :     // The goal here is to try to keep groups of rectangles that are vertically
      68             :     // discontiguous as separate rectangles in the final region. This is
      69             :     // simple and fast to implement and page contents tend to vary more
      70             :     // vertically than horizontally (which is why our rectangles are stored
      71             :     // sorted by y-coordinate, too).
      72             :     //
      73             :     // Note: if boxes share y1 because of the canonical representation they
      74             :     // will share y2
      75         947 :     while ((src < (n)) && boxes[dest].y1 == boxes[src].y1) {
      76             :       // merge box[i] and box[i+1]
      77         359 :       boxes[dest].x2 = boxes[src].x2;
      78         359 :       src++;
      79             :     }
      80         229 :     if (src < n) {
      81         204 :       dest++;
      82         204 :       boxes[dest] = boxes[src];
      83             :     }
      84             :   }
      85             : 
      86          59 :   uint32_t reducedCount = dest+1;
      87             :   // pixman has a special representation for
      88             :   // regions of 1 rectangle. So just use the
      89             :   // bounds in that case
      90          59 :   if (reducedCount > 1 && reducedCount <= aMaxRects) {
      91             :     // reach into pixman and lower the number
      92             :     // of rects stored in data.
      93          59 :     mImpl.data->numRects = reducedCount;
      94             :   } else {
      95           0 :     *this = GetBounds();
      96             :   }
      97             : }
      98             : 
      99             : // compute the covered area difference between two rows.
     100             : // by iterating over both rows simultaneously and adding up
     101             : // the additional increase in area caused by extending each
     102             : // of the rectangles to the combined height of both rows
     103           0 : static uint32_t ComputeMergedAreaIncrease(pixman_box32_t *topRects,
     104             :                                      pixman_box32_t *topRectsEnd,
     105             :                                      pixman_box32_t *bottomRects,
     106             :                                      pixman_box32_t *bottomRectsEnd)
     107             : {
     108           0 :   uint32_t totalArea = 0;
     109             :   struct pt {
     110             :     int32_t x, y;
     111             :   };
     112             : 
     113             : 
     114           0 :   pt *i = (pt*)topRects;
     115           0 :   pt *end_i = (pt*)topRectsEnd;
     116           0 :   pt *j = (pt*)bottomRects;
     117           0 :   pt *end_j = (pt*)bottomRectsEnd;
     118           0 :   bool top = false;
     119           0 :   bool bottom = false;
     120             : 
     121           0 :   int cur_x = i->x;
     122           0 :   bool top_next = top;
     123           0 :   bool bottom_next = bottom;
     124             :   //XXX: we could probably simplify this condition and perhaps move it into the loop below
     125           0 :   if (j->x < cur_x) {
     126           0 :     cur_x = j->x;
     127           0 :     j++;
     128           0 :     bottom_next = !bottom;
     129           0 :   } else if (j->x == cur_x) {
     130           0 :     i++;
     131           0 :     top_next = !top;
     132           0 :     bottom_next = !bottom;
     133           0 :     j++;
     134             :   } else {
     135           0 :     top_next = !top;
     136           0 :     i++;
     137             :   }
     138             : 
     139           0 :   int topRectsHeight = topRects->y2 - topRects->y1;
     140           0 :   int bottomRectsHeight = bottomRects->y2 - bottomRects->y1;
     141           0 :   int inbetweenHeight = bottomRects->y1 - topRects->y2;
     142           0 :   int width = cur_x;
     143             :   // top and bottom are the in-status to the left of cur_x
     144           0 :   do {
     145           0 :     if (top && !bottom) {
     146           0 :       totalArea += (inbetweenHeight+bottomRectsHeight)*width;
     147           0 :     } else if (bottom && !top) {
     148           0 :       totalArea += (inbetweenHeight+topRectsHeight)*width;
     149           0 :     } else if (bottom && top) {
     150           0 :       totalArea += (inbetweenHeight)*width;
     151             :     }
     152           0 :     top = top_next;
     153           0 :     bottom = bottom_next;
     154             :     // find the next edge
     155           0 :     if (i->x < j->x) {
     156           0 :       top_next = !top;
     157           0 :       width = i->x - cur_x;
     158           0 :       cur_x = i->x;
     159           0 :       i++;
     160           0 :     } else if (j->x < i->x) {
     161           0 :       bottom_next = !bottom;
     162           0 :       width = j->x - cur_x;
     163           0 :       cur_x = j->x;
     164           0 :       j++;
     165             :     } else { // i->x == j->x
     166           0 :       top_next = !top;
     167           0 :       bottom_next = !bottom;
     168           0 :       width = i->x - cur_x;
     169           0 :       cur_x = i->x;
     170           0 :       i++;
     171           0 :       j++;
     172             :     }
     173           0 :   } while (i < end_i && j < end_j);
     174             : 
     175             :   // handle any remaining rects
     176           0 :   while (i < end_i) {
     177           0 :     width = i->x - cur_x;
     178           0 :     cur_x = i->x;
     179           0 :     i++;
     180           0 :     if (top)
     181           0 :       totalArea += (inbetweenHeight+bottomRectsHeight)*width;
     182           0 :     top = !top;
     183             :   }
     184             : 
     185           0 :   while (j < end_j) {
     186           0 :     width = j->x - cur_x;
     187           0 :     cur_x = j->x;
     188           0 :     j++;
     189           0 :     if (bottom)
     190           0 :       totalArea += (inbetweenHeight+topRectsHeight)*width;
     191           0 :     bottom = !bottom;
     192             :   }
     193           0 :   return totalArea;
     194             : }
     195             : 
     196             : static pixman_box32_t *
     197           0 : CopyRow(pixman_box32_t *dest_it, pixman_box32_t *src_start, pixman_box32_t *src_end)
     198             : {
     199             :     // XXX: std::copy
     200           0 :     pixman_box32_t *src_it = src_start;
     201           0 :     while (src_it < src_end) {
     202           0 :         *dest_it++ = *src_it++;
     203             :     }
     204           0 :     return dest_it;
     205             : }
     206             : 
     207             : 
     208             : #define WRITE_RECT(x1, x2, y1, y2) \
     209             :     do {                    \
     210             :          tmpRect->x1 = x1;  \
     211             :          tmpRect->x2 = x2;  \
     212             :          tmpRect->y1 = y1;  \
     213             :          tmpRect->y2 = y2;  \
     214             :          tmpRect++;         \
     215             :     } while (0)
     216             : 
     217             : /* If 'r' overlaps the current rect, then expand the current rect to include
     218             :  * it. Otherwise write the current rect out to tmpRect, and set r as the
     219             :  * updated current rect. */
     220             : #define MERGE_RECT(r)                 \
     221             :     do {                              \
     222             :       if (r->x1 <= x2) {              \
     223             :           if (x2 < r->x2)             \
     224             :               x2 = r->x2;             \
     225             :       } else {                        \
     226             :           WRITE_RECT(x1, x2, y1, y2); \
     227             :           x1 = r->x1;                 \
     228             :           x2 = r->x2;                 \
     229             :       }                               \
     230             :       r++;                            \
     231             :     } while (0)
     232             : 
     233             : 
     234             : /* Can we merge two sets of rects without extra space?
     235             :  * Yes, but not easily. We can even do it stably
     236             :  * but we don't need that property.
     237             :  *
     238             :  * This is written in the style of pixman_region_union_o */
     239             : static pixman_box32_t *
     240           0 : MergeRects(pixman_box32_t *r1,
     241             :            pixman_box32_t *r1_end,
     242             :            pixman_box32_t *r2,
     243             :            pixman_box32_t *r2_end,
     244             :            pixman_box32_t *tmpRect)
     245             : {
     246             :     /* This routine works by maintaining the current
     247             :      * rectangle in x1,x2,y1,y2 and either merging
     248             :      * in the left most rectangle if it overlaps or
     249             :      * outputing the current rectangle and setting
     250             :      * it to the the left most one */
     251           0 :     const int y1 = r1->y1;
     252           0 :     const int y2 = r2->y2;
     253             :     int x1;
     254             :     int x2;
     255             : 
     256             :     /* Find the left-most edge */
     257           0 :     if (r1->x1 < r2->x1) {
     258           0 :         x1 = r1->x1;
     259           0 :         x2 = r1->x2;
     260           0 :         r1++;
     261             :     } else {
     262           0 :         x1 = r2->x1;
     263           0 :         x2 = r2->x2;
     264           0 :         r2++;
     265             :     }
     266             : 
     267           0 :     while (r1 != r1_end && r2 != r2_end) {
     268             :         /* Find and merge the left-most rectangle */
     269           0 :         if (r1->x1 < r2->x1)
     270           0 :             MERGE_RECT (r1);
     271             :         else
     272           0 :             MERGE_RECT (r2);
     273             :     }
     274             : 
     275             :     /* Finish up any left overs */
     276           0 :     if (r1 != r1_end) {
     277           0 :         do {
     278           0 :             MERGE_RECT (r1);
     279           0 :         } while (r1 != r1_end);
     280           0 :     } else if (r2 != r2_end) {
     281           0 :         do {
     282           0 :             MERGE_RECT(r2);
     283           0 :         } while (r2 != r2_end);
     284             :     }
     285             : 
     286             :     /* Finish up the last rectangle */
     287           0 :     WRITE_RECT(x1, x2, y1, y2);
     288             : 
     289           0 :     return tmpRect;
     290             : }
     291             : 
     292           0 : void nsRegion::SimplifyOutwardByArea(uint32_t aThreshold)
     293             : {
     294             : 
     295             :   pixman_box32_t *boxes;
     296             :   int n;
     297           0 :   boxes = pixman_region32_rectangles(&mImpl, &n);
     298             : 
     299             :   // if we have no rectangles then we're done
     300           0 :   if (!n)
     301           0 :     return;
     302             : 
     303           0 :   pixman_box32_t *end = boxes + n;
     304           0 :   pixman_box32_t *topRectsEnd = boxes+1;
     305           0 :   pixman_box32_t *topRects = boxes;
     306             : 
     307             :   // we need some temporary storage for merging both rows of rectangles
     308           0 :   AutoTArray<pixman_box32_t, 10> tmpStorage;
     309           0 :   tmpStorage.SetCapacity(n);
     310           0 :   pixman_box32_t *tmpRect = tmpStorage.Elements();
     311             : 
     312           0 :   pixman_box32_t *destRect = boxes;
     313           0 :   pixman_box32_t *rect = tmpRect;
     314             :   // find the end of the first span of rectangles
     315           0 :   while (topRectsEnd < end && topRectsEnd->y1 == topRects->y1) {
     316           0 :     topRectsEnd++;
     317             :   }
     318             : 
     319             :   // if we only have one row we are done
     320           0 :   if (topRectsEnd == end)
     321           0 :     return;
     322             : 
     323           0 :   pixman_box32_t *bottomRects = topRectsEnd;
     324           0 :   pixman_box32_t *bottomRectsEnd = bottomRects+1;
     325           0 :   do {
     326             :     // find the end of the bottom span of rectangles
     327           0 :     while (bottomRectsEnd < end && bottomRectsEnd->y1 == bottomRects->y1) {
     328           0 :       bottomRectsEnd++;
     329             :     }
     330             :     uint32_t totalArea = ComputeMergedAreaIncrease(topRects, topRectsEnd,
     331           0 :                                                    bottomRects, bottomRectsEnd);
     332             : 
     333           0 :     if (totalArea <= aThreshold) {
     334             :       // merge the rects into tmpRect
     335           0 :       rect = MergeRects(topRects, topRectsEnd, bottomRects, bottomRectsEnd, tmpRect);
     336             : 
     337             :       // set topRects to where the newly merged rects will be so that we use them
     338             :       // as our next set of topRects
     339           0 :       topRects = destRect;
     340             :       // copy the merged rects back into the destination
     341           0 :       topRectsEnd = CopyRow(destRect, tmpRect, rect);
     342             :     } else {
     343             :       // copy the unmerged rects
     344           0 :       destRect = CopyRow(destRect, topRects, topRectsEnd);
     345             : 
     346           0 :       topRects = bottomRects;
     347           0 :       topRectsEnd = bottomRectsEnd;
     348           0 :       if (bottomRectsEnd == end) {
     349             :         // copy the last row when we are done
     350           0 :         topRectsEnd = CopyRow(destRect, topRects, topRectsEnd);
     351             :       }
     352             :     }
     353           0 :     bottomRects = bottomRectsEnd;
     354           0 :   } while (bottomRectsEnd != end);
     355             : 
     356             : 
     357           0 :   uint32_t reducedCount = topRectsEnd - pixman_region32_rectangles(&this->mImpl, &n);
     358             :   // pixman has a special representation for
     359             :   // regions of 1 rectangle. So just use the
     360             :   // bounds in that case
     361           0 :   if (reducedCount > 1) {
     362             :     // reach into pixman and lower the number
     363             :     // of rects stored in data.
     364           0 :     this->mImpl.data->numRects = reducedCount;
     365             :   } else {
     366           0 :     *this = GetBounds();
     367             :   }
     368             : }
     369             : 
     370             : 
     371             : typedef void (*visit_fn)(void *closure, VisitSide side, int x1, int y1, int x2, int y2);
     372             : 
     373           0 : static bool VisitNextEdgeBetweenRect(visit_fn visit, void *closure, VisitSide side,
     374             :                                      pixman_box32_t *&r1, pixman_box32_t *&r2, const int y, int &x1)
     375             : {
     376             :   // check for overlap
     377           0 :   if (r1->x2 >= r2->x1) {
     378           0 :     MOZ_ASSERT(r2->x1 >= x1);
     379           0 :     visit(closure, side, x1, y, r2->x1, y);
     380             : 
     381             :     // find the rect that ends first or always drop the one that comes first?
     382           0 :     if (r1->x2 < r2->x2) {
     383           0 :       x1 = r1->x2;
     384           0 :       r1++;
     385             :     } else {
     386           0 :       x1 = r2->x2;
     387           0 :       r2++;
     388             :     }
     389           0 :     return true;
     390             :   } else {
     391           0 :     MOZ_ASSERT(r1->x2 < r2->x2);
     392             :     // we handle the corners by just extending the top and bottom edges
     393           0 :     visit(closure, side, x1, y, r1->x2+1, y);
     394           0 :     r1++;
     395             :     // we assign x1 because we can assume that x1 <= r2->x1 - 1
     396             :     // However the caller may know better and if so, may update
     397             :     // x1 to r1->x1
     398           0 :     x1 = r2->x1 - 1;
     399           0 :     return false;
     400             :   }
     401             : }
     402             : 
     403             : //XXX: if we need to this can compute the end of the row
     404             : static void
     405           0 : VisitSides(visit_fn visit, void *closure, pixman_box32_t *r, pixman_box32_t *r_end)
     406             : {
     407             :   // XXX: we can drop LEFT/RIGHT and just use the orientation
     408             :   // of the line if it makes sense
     409           0 :   while (r != r_end) {
     410           0 :     visit(closure, VisitSide::LEFT, r->x1, r->y1, r->x1, r->y2);
     411           0 :     visit(closure, VisitSide::RIGHT, r->x2, r->y1, r->x2, r->y2);
     412           0 :     r++;
     413             :   }
     414           0 : }
     415             : 
     416             : static void
     417           0 : VisitAbove(visit_fn visit, void *closure, pixman_box32_t *r, pixman_box32_t *r_end)
     418             : {
     419           0 :   while (r != r_end) {
     420           0 :     visit(closure, VisitSide::TOP, r->x1-1, r->y1, r->x2+1, r->y1);
     421           0 :     r++;
     422             :   }
     423           0 : }
     424             : 
     425             : static void
     426           0 : VisitBelow(visit_fn visit, void *closure, pixman_box32_t *r, pixman_box32_t *r_end)
     427             : {
     428           0 :   while (r != r_end) {
     429           0 :     visit(closure, VisitSide::BOTTOM, r->x1-1, r->y2, r->x2+1, r->y2);
     430           0 :     r++;
     431             :   }
     432           0 : }
     433             : 
     434             : static pixman_box32_t *
     435           0 : VisitInbetween(visit_fn visit, void *closure, pixman_box32_t *r1,
     436             :                pixman_box32_t *r1_end,
     437             :                pixman_box32_t *r2,
     438             :                pixman_box32_t *r2_end)
     439             : {
     440           0 :   const int y = r1->y2;
     441             :   int x1;
     442             : 
     443           0 :   bool overlap = false;
     444           0 :   while (r1 != r1_end && r2 != r2_end) {
     445           0 :     if (!overlap) {
     446             :       /* Find the left-most edge */
     447           0 :       if (r1->x1 < r2->x1) {
     448           0 :         x1 = r1->x1 - 1;
     449             :       } else {
     450           0 :         x1 = r2->x1 - 1;
     451             :       }
     452             :     }
     453             : 
     454           0 :     MOZ_ASSERT((x1 >= (r1->x1 - 1)) || (x1 >= (r2->x1 - 1)));
     455           0 :     if (r1->x1 < r2->x1) {
     456           0 :       overlap = VisitNextEdgeBetweenRect(visit, closure, VisitSide::BOTTOM, r1, r2, y, x1);
     457             :     } else {
     458           0 :       overlap = VisitNextEdgeBetweenRect(visit, closure, VisitSide::TOP, r2, r1, y, x1);
     459             :     }
     460             :   }
     461             : 
     462             :   /* Finish up which ever row has remaining rects*/
     463           0 :   if (r1 != r1_end) {
     464             :     // top row
     465             :     do {
     466           0 :       visit(closure, VisitSide::BOTTOM, x1, y, r1->x2 + 1, y);
     467           0 :       r1++;
     468           0 :       if (r1 == r1_end)
     469           0 :         break;
     470           0 :       x1 = r1->x1 - 1;
     471             :     } while (true);
     472           0 :   } else if (r2 != r2_end) {
     473             :     // bottom row
     474             :     do {
     475           0 :       visit(closure, VisitSide::TOP, x1, y, r2->x2 + 1, y);
     476           0 :       r2++;
     477           0 :       if (r2 == r2_end)
     478           0 :         break;
     479           0 :       x1 = r2->x1 - 1;
     480             :     } while (true);
     481             :   }
     482             : 
     483           0 :   return 0;
     484             : }
     485             : 
     486           0 : void nsRegion::VisitEdges (visit_fn visit, void *closure)
     487             : {
     488             :   pixman_box32_t *boxes;
     489             :   int n;
     490           0 :   boxes = pixman_region32_rectangles(&mImpl, &n);
     491             : 
     492             :   // if we have no rectangles then we're done
     493           0 :   if (!n)
     494           0 :     return;
     495             : 
     496           0 :   pixman_box32_t *end = boxes + n;
     497           0 :   pixman_box32_t *topRectsEnd = boxes + 1;
     498           0 :   pixman_box32_t *topRects = boxes;
     499             : 
     500             :   // find the end of the first span of rectangles
     501           0 :   while (topRectsEnd < end && topRectsEnd->y1 == topRects->y1) {
     502           0 :     topRectsEnd++;
     503             :   }
     504             : 
     505             :   // In order to properly handle convex corners we always visit the sides first
     506             :   // that way when we visit the corners we can pad using the value from the sides
     507           0 :   VisitSides(visit, closure, topRects, topRectsEnd);
     508             : 
     509           0 :   VisitAbove(visit, closure, topRects, topRectsEnd);
     510             : 
     511           0 :   pixman_box32_t *bottomRects = topRects;
     512           0 :   pixman_box32_t *bottomRectsEnd = topRectsEnd;
     513           0 :   if (topRectsEnd != end) {
     514           0 :     do {
     515             :       // find the next row of rects
     516           0 :       bottomRects = topRectsEnd;
     517           0 :       bottomRectsEnd = topRectsEnd + 1;
     518           0 :       while (bottomRectsEnd < end && bottomRectsEnd->y1 == bottomRects->y1) {
     519           0 :         bottomRectsEnd++;
     520             :       }
     521             : 
     522           0 :       VisitSides(visit, closure, bottomRects, bottomRectsEnd);
     523             : 
     524           0 :       if (topRects->y2 == bottomRects->y1) {
     525             :         VisitInbetween(visit, closure, topRects, topRectsEnd,
     526           0 :                                        bottomRects, bottomRectsEnd);
     527             :       } else {
     528           0 :         VisitBelow(visit, closure, topRects, topRectsEnd);
     529           0 :         VisitAbove(visit, closure, bottomRects, bottomRectsEnd);
     530             :       }
     531             : 
     532           0 :       topRects = bottomRects;
     533           0 :       topRectsEnd = bottomRectsEnd;
     534           0 :     } while (bottomRectsEnd != end);
     535             :   }
     536             : 
     537             :   // the bottom of the region doesn't touch anything else so we
     538             :   // can always visit it at the end
     539           0 :   VisitBelow(visit, closure, bottomRects, bottomRectsEnd);
     540             : }
     541             : 
     542             : 
     543           0 : void nsRegion::SimplifyInward (uint32_t aMaxRects)
     544             : {
     545           0 :   NS_ASSERTION(aMaxRects >= 1, "Invalid max rect count");
     546             : 
     547           0 :   if (GetNumRects() <= aMaxRects)
     548           0 :     return;
     549             : 
     550           0 :   SetEmpty();
     551             : }
     552             : 
     553          35 : uint64_t nsRegion::Area () const
     554             : {
     555          35 :   uint64_t area = 0;
     556          35 :   for (auto iter = RectIter(); !iter.Done(); iter.Next()) {
     557           0 :     const nsRect& rect = iter.Get();
     558           0 :     area += uint64_t(rect.width) * rect.height;
     559             :   }
     560          35 :   return area;
     561             : }
     562             : 
     563         595 : nsRegion& nsRegion::ScaleRoundOut (float aXScale, float aYScale)
     564             : {
     565        1189 :   if (mozilla::gfx::FuzzyEqual(aXScale, 1.0f) &&
     566         594 :       mozilla::gfx::FuzzyEqual(aYScale, 1.0f)) {
     567         594 :     return *this;
     568             :   }
     569             : 
     570             :   int n;
     571           1 :   pixman_box32_t *boxes = pixman_region32_rectangles(&mImpl, &n);
     572           2 :   for (int i=0; i<n; i++) {
     573           2 :     nsRect rect = BoxToRect(boxes[i]);
     574           1 :     rect.ScaleRoundOut(aXScale, aYScale);
     575           1 :     boxes[i] = RectToBox(rect);
     576             :   }
     577             : 
     578             :   pixman_region32_t region;
     579             :   // This will union all of the rectangles and runs in about O(n lg(n))
     580           1 :   pixman_region32_init_rects(&region, boxes, n);
     581             : 
     582           1 :   pixman_region32_fini(&mImpl);
     583           1 :   mImpl = region;
     584           1 :   return *this;
     585             : }
     586             : 
     587          60 : nsRegion& nsRegion::ScaleInverseRoundOut (float aXScale, float aYScale)
     588             : {
     589             :   int n;
     590          60 :   pixman_box32_t *boxes = pixman_region32_rectangles(&mImpl, &n);
     591         150 :   for (int i=0; i<n; i++) {
     592         180 :     nsRect rect = BoxToRect(boxes[i]);
     593          90 :     rect.ScaleInverseRoundOut(aXScale, aYScale);
     594          90 :     boxes[i] = RectToBox(rect);
     595             :   }
     596             : 
     597             :   pixman_region32_t region;
     598             :   // This will union all of the rectangles and runs in about O(n lg(n))
     599          60 :   pixman_region32_init_rects(&region, boxes, n);
     600             : 
     601          60 :   pixman_region32_fini(&mImpl);
     602          60 :   mImpl = region;
     603          60 :   return *this;
     604             : }
     605             : 
     606             : static mozilla::gfx::IntRect
     607         247 : TransformRect(const mozilla::gfx::IntRect& aRect, const mozilla::gfx::Matrix4x4& aTransform)
     608             : {
     609         247 :     if (aRect.IsEmpty()) {
     610           0 :         return mozilla::gfx::IntRect();
     611             :     }
     612             : 
     613         247 :     mozilla::gfx::RectDouble rect(aRect.x, aRect.y, aRect.width, aRect.height);
     614         247 :     rect = aTransform.TransformAndClipBounds(rect, mozilla::gfx::RectDouble::MaxIntRect());
     615         247 :     rect.RoundOut();
     616             : 
     617         247 :     mozilla::gfx::IntRect intRect;
     618         247 :     if (!gfxUtils::GfxRectToIntRect(ThebesRect(rect), &intRect)) {
     619           0 :         return mozilla::gfx::IntRect();
     620             :     }
     621             : 
     622         247 :     return intRect;
     623             : }
     624             : 
     625         418 : nsRegion& nsRegion::Transform (const mozilla::gfx::Matrix4x4 &aTransform)
     626             : {
     627             :   int n;
     628         418 :   pixman_box32_t *boxes = pixman_region32_rectangles(&mImpl, &n);
     629         665 :   for (int i=0; i<n; i++) {
     630         494 :     nsRect rect = BoxToRect(boxes[i]);
     631         247 :     boxes[i] = RectToBox(nsIntRegion::ToRect(TransformRect(nsIntRegion::FromRect(rect), aTransform)));
     632             :   }
     633             : 
     634             :   pixman_region32_t region;
     635             :   // This will union all of the rectangles and runs in about O(n lg(n))
     636         418 :   pixman_region32_init_rects(&region, boxes, n);
     637             : 
     638         418 :   pixman_region32_fini(&mImpl);
     639         418 :   mImpl = region;
     640         418 :   return *this;
     641             : }
     642             : 
     643             : 
     644           0 : nsRegion nsRegion::ScaleToOtherAppUnitsRoundOut (int32_t aFromAPP, int32_t aToAPP) const
     645             : {
     646           0 :   if (aFromAPP == aToAPP) {
     647           0 :     return *this;
     648             :   }
     649             : 
     650           0 :   nsRegion region = *this;
     651             :   int n;
     652           0 :   pixman_box32_t *boxes = pixman_region32_rectangles(&region.mImpl, &n);
     653           0 :   for (int i=0; i<n; i++) {
     654           0 :     nsRect rect = BoxToRect(boxes[i]);
     655           0 :     rect = rect.ScaleToOtherAppUnitsRoundOut(aFromAPP, aToAPP);
     656           0 :     boxes[i] = RectToBox(rect);
     657             :   }
     658             : 
     659             :   pixman_region32_t pixmanRegion;
     660             :   // This will union all of the rectangles and runs in about O(n lg(n))
     661           0 :   pixman_region32_init_rects(&pixmanRegion, boxes, n);
     662             : 
     663           0 :   pixman_region32_fini(&region.mImpl);
     664           0 :   region.mImpl = pixmanRegion;
     665           0 :   return region;
     666             : }
     667             : 
     668           0 : nsRegion nsRegion::ScaleToOtherAppUnitsRoundIn (int32_t aFromAPP, int32_t aToAPP) const
     669             : {
     670           0 :   if (aFromAPP == aToAPP) {
     671           0 :     return *this;
     672             :   }
     673             : 
     674           0 :   nsRegion region = *this;
     675             :   int n;
     676           0 :   pixman_box32_t *boxes = pixman_region32_rectangles(&region.mImpl, &n);
     677           0 :   for (int i=0; i<n; i++) {
     678           0 :     nsRect rect = BoxToRect(boxes[i]);
     679           0 :     rect = rect.ScaleToOtherAppUnitsRoundIn(aFromAPP, aToAPP);
     680           0 :     boxes[i] = RectToBox(rect);
     681             :   }
     682             : 
     683             :   pixman_region32_t pixmanRegion;
     684             :   // This will union all of the rectangles and runs in about O(n lg(n))
     685           0 :   pixman_region32_init_rects(&pixmanRegion, boxes, n);
     686             : 
     687           0 :   pixman_region32_fini(&region.mImpl);
     688           0 :   region.mImpl = pixmanRegion;
     689           0 :   return region;
     690             : }
     691             : 
     692          26 : nsIntRegion nsRegion::ToPixels (nscoord aAppUnitsPerPixel, bool aOutsidePixels) const
     693             : {
     694          52 :   nsRegion region = *this;
     695             :   int n;
     696          26 :   pixman_box32_t *boxes = pixman_region32_rectangles(&region.mImpl, &n);
     697          26 :   for (int i=0; i<n; i++) {
     698           0 :     nsRect rect = BoxToRect(boxes[i]);
     699           0 :     mozilla::gfx::IntRect deviceRect;
     700           0 :     if (aOutsidePixels)
     701           0 :       deviceRect = rect.ToOutsidePixels(aAppUnitsPerPixel);
     702             :     else
     703           0 :       deviceRect = rect.ToNearestPixels(aAppUnitsPerPixel);
     704             : 
     705           0 :     boxes[i] = RectToBox(deviceRect);
     706             :   }
     707             : 
     708          26 :   nsIntRegion intRegion;
     709          26 :   pixman_region32_fini(&intRegion.mImpl.mImpl);
     710             :   // This will union all of the rectangles and runs in about O(n lg(n))
     711          26 :   pixman_region32_init_rects(&intRegion.mImpl.mImpl, boxes, n);
     712             : 
     713          52 :   return intRegion;
     714             : }
     715             : 
     716           0 : nsIntRegion nsRegion::ToOutsidePixels (nscoord aAppUnitsPerPixel) const
     717             : {
     718           0 :   return ToPixels(aAppUnitsPerPixel, true);
     719             : }
     720             : 
     721          26 : nsIntRegion nsRegion::ToNearestPixels (nscoord aAppUnitsPerPixel) const
     722             : {
     723          26 :   return ToPixels(aAppUnitsPerPixel, false);
     724             : }
     725             : 
     726         159 : nsIntRegion nsRegion::ScaleToNearestPixels (float aScaleX, float aScaleY,
     727             :                                             nscoord aAppUnitsPerPixel) const
     728             : {
     729         159 :   nsIntRegion result;
     730         318 :   for (auto iter = RectIter(); !iter.Done(); iter.Next()) {
     731             :     mozilla::gfx::IntRect deviceRect =
     732         159 :       iter.Get().ScaleToNearestPixels(aScaleX, aScaleY, aAppUnitsPerPixel);
     733         159 :     result.Or(result, deviceRect);
     734             :   }
     735         159 :   return result;
     736             : }
     737             : 
     738         874 : nsIntRegion nsRegion::ScaleToOutsidePixels (float aScaleX, float aScaleY,
     739             :                                             nscoord aAppUnitsPerPixel) const
     740             : {
     741             :   // make a copy of the region so that we can mutate it inplace
     742        1748 :   nsRegion region = *this;
     743             :   int n;
     744         874 :   pixman_box32_t *boxes = pixman_region32_rectangles(&region.mImpl, &n);
     745         874 :   boxes = pixman_region32_rectangles(&region.mImpl, &n);
     746        1283 :   for (int i=0; i<n; i++) {
     747         818 :     nsRect rect = BoxToRect(boxes[i]);
     748         409 :     mozilla::gfx::IntRect irect = rect.ScaleToOutsidePixels(aScaleX, aScaleY, aAppUnitsPerPixel);
     749         409 :     boxes[i] = RectToBox(irect);
     750             :   }
     751             : 
     752         874 :   nsIntRegion iRegion;
     753             :   // clear out the initial pixman_region so that we can replace it below
     754         874 :   pixman_region32_fini(&iRegion.mImpl.mImpl);
     755             :   // This will union all of the rectangles and runs in about O(n lg(n))
     756         874 :   pixman_region32_init_rects(&iRegion.mImpl.mImpl, boxes, n);
     757             : 
     758        1748 :   return iRegion;
     759             : }
     760             : 
     761          26 : nsIntRegion nsRegion::ScaleToInsidePixels (float aScaleX, float aScaleY,
     762             :                                            nscoord aAppUnitsPerPixel) const
     763             : {
     764             :   /* When scaling a rect, walk forward through the rect list up until the y value is greater
     765             :    * than the current rect's YMost() value.
     766             :    *
     767             :    * For each rect found, check if the rects have a touching edge (in unscaled coordinates),
     768             :    * and if one edge is entirely contained within the other.
     769             :    *
     770             :    * If it is, then the contained edge can be moved (in scaled pixels) to ensure that no
     771             :    * gap exists.
     772             :    *
     773             :    * Since this could be potentially expensive - O(n^2), we only attempt this algorithm
     774             :    * for the first rect.
     775             :    */
     776             : 
     777             :   // make a copy of this region so that we can mutate it in place
     778          52 :   nsRegion region = *this;
     779             :   int n;
     780          26 :   pixman_box32_t *boxes = pixman_region32_rectangles(&region.mImpl, &n);
     781             : 
     782          26 :   nsIntRegion intRegion;
     783          26 :   if (n) {
     784          52 :     nsRect first = BoxToRect(boxes[0]);
     785             :     mozilla::gfx::IntRect firstDeviceRect =
     786          26 :       first.ScaleToInsidePixels(aScaleX, aScaleY, aAppUnitsPerPixel);
     787             : 
     788          26 :     for (int i=1; i<n; i++) {
     789           0 :       nsRect rect = nsRect(boxes[i].x1, boxes[i].y1,
     790           0 :           boxes[i].x2 - boxes[i].x1,
     791           0 :           boxes[i].y2 - boxes[i].y1);
     792             :       mozilla::gfx::IntRect deviceRect =
     793           0 :         rect.ScaleToInsidePixels(aScaleX, aScaleY, aAppUnitsPerPixel);
     794             : 
     795           0 :       if (rect.y <= first.YMost()) {
     796           0 :         if (rect.XMost() == first.x && rect.YMost() <= first.YMost()) {
     797             :           // rect is touching on the left edge of the first rect and contained within
     798             :           // the length of its left edge
     799           0 :           deviceRect.SetRightEdge(firstDeviceRect.x);
     800           0 :         } else if (rect.x == first.XMost() && rect.YMost() <= first.YMost()) {
     801             :           // rect is touching on the right edge of the first rect and contained within
     802             :           // the length of its right edge
     803           0 :           deviceRect.SetLeftEdge(firstDeviceRect.XMost());
     804           0 :         } else if (rect.y == first.YMost()) {
     805             :           // The bottom of the first rect is on the same line as the top of rect, but
     806             :           // they aren't necessarily contained.
     807           0 :           if (rect.x <= first.x && rect.XMost() >= first.XMost()) {
     808             :             // The top of rect contains the bottom of the first rect
     809           0 :             firstDeviceRect.SetBottomEdge(deviceRect.y);
     810           0 :           } else if (rect.x >= first.x && rect.XMost() <= first.XMost()) {
     811             :             // The bottom of the first contains the top of rect
     812           0 :             deviceRect.SetTopEdge(firstDeviceRect.YMost());
     813             :           }
     814             :         }
     815             :       }
     816             : 
     817           0 :       boxes[i] = RectToBox(deviceRect);
     818             :     }
     819             : 
     820          26 :     boxes[0] = RectToBox(firstDeviceRect);
     821             : 
     822          26 :     pixman_region32_fini(&intRegion.mImpl.mImpl);
     823             :     // This will union all of the rectangles and runs in about O(n lg(n))
     824          26 :     pixman_region32_init_rects(&intRegion.mImpl.mImpl, boxes, n);
     825             :   }
     826          52 :   return intRegion;
     827             : 
     828             : }
     829             : 
     830             : // A cell's "value" is a pair consisting of
     831             : // a) the area of the subrectangle it corresponds to, if it's in
     832             : // aContainingRect and in the region, 0 otherwise
     833             : // b) the area of the subrectangle it corresponds to, if it's in the region,
     834             : // 0 otherwise
     835             : // Addition, subtraction and identity are defined on these values in the
     836             : // obvious way. Partial order is lexicographic.
     837             : // A "large negative value" is defined with large negative numbers for both
     838             : // fields of the pair. This negative value has the property that adding any
     839             : // number of non-negative values to it always results in a negative value.
     840             : //
     841             : // The GetLargestRectangle algorithm works in three phases:
     842             : //  1) Convert the region into a grid by adding vertical/horizontal lines for
     843             : //     each edge of each rectangle in the region.
     844             : //  2) For each rectangle in the region, for each cell it contains, set that
     845             : //     cells's value as described above.
     846             : //  3) Calculate the submatrix with the largest sum such that none of its cells
     847             : //     contain any 0s (empty regions). The rectangle represented by the
     848             : //     submatrix is the largest rectangle in the region.
     849             : //
     850             : // Let k be the number of rectangles in the region.
     851             : // Let m be the height of the grid generated in step 1.
     852             : // Let n be the width of the grid generated in step 1.
     853             : //
     854             : // Step 1 is O(k) in time and O(m+n) in space for the sparse grid.
     855             : // Step 2 is O(mn) in time and O(mn) in additional space for the full grid.
     856             : // Step 3 is O(m^2 n) in time and O(mn) in additional space
     857             : //
     858             : // The implementation of steps 1 and 2 are rather straightforward. However our
     859             : // implementation of step 3 uses dynamic programming to achieve its efficiency.
     860             : //
     861             : // Psuedo code for step 3 is as follows where G is the grid from step 1 and A
     862             : // is the array from step 2:
     863             : // Phase3 = function (G, A, m, n) {
     864             : //   let (t,b,l,r,_) = MaxSum2D(A,m,n)
     865             : //   return rect(G[t],G[l],G[r],G[b]);
     866             : // }
     867             : // MaxSum2D = function (A, m, n) {
     868             : //   S = array(m+1,n+1)
     869             : //   S[0][i] = 0 for i in [0,n]
     870             : //   S[j][0] = 0 for j in [0,m]
     871             : //   S[j][i] = (if A[j-1][i-1] = 0 then some large negative value else A[j-1][i-1])
     872             : //           + S[j-1][n] + S[j][i-1] - S[j-1][i-1]
     873             : //
     874             : //   // top, bottom, left, right, area
     875             : //   var maxRect = (-1, -1, -1, -1, 0);
     876             : //
     877             : //   for all (m',m'') in [0, m]^2 {
     878             : //     let B = { S[m'][i] - S[m''][i] | 0 <= i <= n }
     879             : //     let ((l,r),area) = MaxSum1D(B,n+1)
     880             : //     if (area > maxRect.area) {
     881             : //       maxRect := (m', m'', l, r, area)
     882             : //     }
     883             : //   }
     884             : //
     885             : //   return maxRect;
     886             : // }
     887             : //
     888             : // Originally taken from Improved algorithms for the k-maximum subarray problem
     889             : // for small k - SE Bae, T Takaoka but modified to show the explicit tracking
     890             : // of indices and we already have the prefix sums from our one call site so
     891             : // there's no need to construct them.
     892             : // MaxSum1D = function (A,n) {
     893             : //   var minIdx = 0;
     894             : //   var min = 0;
     895             : //   var maxIndices = (0,0);
     896             : //   var max = 0;
     897             : //   for i in range(n) {
     898             : //     let cand = A[i] - min;
     899             : //     if (cand > max) {
     900             : //       max := cand;
     901             : //       maxIndices := (minIdx, i)
     902             : //     }
     903             : //     if (min > A[i]) {
     904             : //       min := A[i];
     905             : //       minIdx := i;
     906             : //     }
     907             : //   }
     908             : //   return (minIdx, maxIdx, max);
     909             : // }
     910             : 
     911             : namespace {
     912             :   // This class represents a partitioning of an axis delineated by coordinates.
     913             :   // It internally maintains a sorted array of coordinates.
     914         236 :   class AxisPartition {
     915             :   public:
     916             :     // Adds a new partition at the given coordinate to this partitioning. If
     917             :     // the coordinate is already present in the partitioning, this does nothing.
     918         708 :     void InsertCoord(nscoord c) {
     919         708 :       uint32_t i = mStops.IndexOfFirstElementGt(c);
     920         708 :       if (i == 0 || mStops[i-1] != c) {
     921         472 :         mStops.InsertElementAt(i, c);
     922             :       }
     923         708 :     }
     924             : 
     925             :     // Returns the array index of the given partition point. The partition
     926             :     // point must already be present in the partitioning.
     927         708 :     int32_t IndexOf(nscoord p) const {
     928         708 :       return mStops.BinaryIndexOf(p);
     929             :     }
     930             : 
     931             :     // Returns the partition at the given index which must be non-zero and
     932             :     // less than the number of partitions in this partitioning.
     933         236 :     nscoord StopAt(int32_t index) const {
     934         236 :       return mStops[index];
     935             :     }
     936             : 
     937             :     // Returns the size of the gap between the partition at the given index and
     938             :     // the next partition in this partitioning. If the index is the last index
     939             :     // in the partitioning, the result is undefined.
     940         472 :     nscoord StopSize(int32_t index) const {
     941         472 :       return mStops[index+1] - mStops[index];
     942             :     }
     943             : 
     944             :     // Returns the number of partitions in this partitioning.
     945         118 :     int32_t GetNumStops() const { return mStops.Length(); }
     946             : 
     947             :   private:
     948             :     nsTArray<nscoord> mStops;
     949             :   };
     950             : 
     951             :   const int64_t kVeryLargeNegativeNumber = 0xffff000000000000ll;
     952             : 
     953             :   struct SizePair {
     954             :     int64_t mSizeContainingRect;
     955             :     int64_t mSize;
     956             : 
     957        3894 :     SizePair() : mSizeContainingRect(0), mSize(0) {}
     958             : 
     959         236 :     static SizePair VeryLargeNegative() {
     960         236 :       SizePair result;
     961         236 :       result.mSize = result.mSizeContainingRect = kVeryLargeNegativeNumber;
     962         236 :       return result;
     963             :     }
     964        2478 :     bool operator<(const SizePair& aOther) const {
     965        2478 :       if (mSizeContainingRect < aOther.mSizeContainingRect)
     966         590 :         return true;
     967        1888 :       if (mSizeContainingRect > aOther.mSizeContainingRect)
     968         590 :         return false;
     969        1298 :       return mSize < aOther.mSize;
     970             :     }
     971        2478 :     bool operator>(const SizePair& aOther) const {
     972        2478 :       return aOther.operator<(*this);
     973             :     }
     974        1062 :     SizePair operator+(const SizePair& aOther) const {
     975        1062 :       SizePair result = *this;
     976        1062 :       result.mSizeContainingRect += aOther.mSizeContainingRect;
     977        1062 :       result.mSize += aOther.mSize;
     978        1062 :       return result;
     979             :     }
     980        3009 :     SizePair operator-(const SizePair& aOther) const {
     981        3009 :       SizePair result = *this;
     982        3009 :       result.mSizeContainingRect -= aOther.mSizeContainingRect;
     983        3009 :       result.mSize -= aOther.mSize;
     984        3009 :       return result;
     985             :     }
     986             :   };
     987             : 
     988             :   // Returns the sum and indices of the subarray with the maximum sum of the
     989             :   // given array (A,n), assuming the array is already in prefix sum form.
     990         354 :   SizePair MaxSum1D(const nsTArray<SizePair> &A, int32_t n,
     991             :                     int32_t *minIdx, int32_t *maxIdx) {
     992             :     // The min/max indicies of the largest subarray found so far
     993         354 :     SizePair min, max;
     994         354 :     int32_t currentMinIdx = 0;
     995             : 
     996         354 :     *minIdx = 0;
     997         354 :     *maxIdx = 0;
     998             : 
     999             :     // Because we're given the array in prefix sum form, we know the first
    1000             :     // element is 0
    1001        1416 :     for(int32_t i = 1; i < n; i++) {
    1002        1062 :       SizePair cand = A[i] - min;
    1003        1062 :       if (cand > max) {
    1004         472 :         max = cand;
    1005         472 :         *minIdx = currentMinIdx;
    1006         472 :         *maxIdx = i;
    1007             :       }
    1008        1062 :       if (min > A[i]) {
    1009         590 :         min = A[i];
    1010         590 :         currentMinIdx = i;
    1011             :       }
    1012             :     }
    1013             : 
    1014         354 :     return max;
    1015             :   }
    1016             : } // namespace
    1017             : 
    1018          59 : nsRect nsRegion::GetLargestRectangle (const nsRect& aContainingRect) const {
    1019          59 :   nsRect bestRect;
    1020             : 
    1021          59 :   if (GetNumRects() <= 1) {
    1022           0 :     bestRect = GetBounds();
    1023           0 :     return bestRect;
    1024             :   }
    1025             : 
    1026         118 :   AxisPartition xaxis, yaxis;
    1027             : 
    1028             :   // Step 1: Calculate the grid lines
    1029         236 :   for (auto iter = RectIter(); !iter.Done(); iter.Next()) {
    1030         177 :     const nsRect& rect = iter.Get();
    1031         177 :     xaxis.InsertCoord(rect.x);
    1032         177 :     xaxis.InsertCoord(rect.XMost());
    1033         177 :     yaxis.InsertCoord(rect.y);
    1034         177 :     yaxis.InsertCoord(rect.YMost());
    1035             :   }
    1036          59 :   if (!aContainingRect.IsEmpty()) {
    1037           0 :     xaxis.InsertCoord(aContainingRect.x);
    1038           0 :     xaxis.InsertCoord(aContainingRect.XMost());
    1039           0 :     yaxis.InsertCoord(aContainingRect.y);
    1040           0 :     yaxis.InsertCoord(aContainingRect.YMost());
    1041             :   }
    1042             : 
    1043             :   // Step 2: Fill out the grid with the areas
    1044             :   // Note: due to the ordering of rectangles in the region, it is not always
    1045             :   // possible to combine steps 2 and 3 so we don't try to be clever.
    1046          59 :   int32_t matrixHeight = yaxis.GetNumStops() - 1;
    1047          59 :   int32_t matrixWidth = xaxis.GetNumStops() - 1;
    1048          59 :   int32_t matrixSize = matrixHeight * matrixWidth;
    1049         118 :   nsTArray<SizePair> areas(matrixSize);
    1050          59 :   areas.SetLength(matrixSize);
    1051             : 
    1052         236 :   for (auto iter = RectIter(); !iter.Done(); iter.Next()) {
    1053         177 :     const nsRect& rect = iter.Get();
    1054         177 :     int32_t xstart = xaxis.IndexOf(rect.x);
    1055         177 :     int32_t xend = xaxis.IndexOf(rect.XMost());
    1056         177 :     int32_t y = yaxis.IndexOf(rect.y);
    1057         177 :     int32_t yend = yaxis.IndexOf(rect.YMost());
    1058             : 
    1059         531 :     for (; y < yend; y++) {
    1060         177 :       nscoord height = yaxis.StopSize(y);
    1061         472 :       for (int32_t x = xstart; x < xend; x++) {
    1062         295 :         nscoord width = xaxis.StopSize(x);
    1063         295 :         int64_t size = width*int64_t(height);
    1064         295 :         if (rect.Intersects(aContainingRect)) {
    1065           0 :           areas[y*matrixWidth+x].mSizeContainingRect = size;
    1066             :         }
    1067         295 :         areas[y*matrixWidth+x].mSize = size;
    1068             :       }
    1069             :     }
    1070             :   }
    1071             : 
    1072             :   // Step 3: Find the maximum submatrix sum that does not contain a rectangle
    1073             :   {
    1074             :     // First get the prefix sum array
    1075          59 :     int32_t m = matrixHeight + 1;
    1076          59 :     int32_t n = matrixWidth + 1;
    1077         118 :     nsTArray<SizePair> pareas(m*n);
    1078          59 :     pareas.SetLength(m*n);
    1079         236 :     for (int32_t y = 1; y < m; y++) {
    1080         708 :       for (int32_t x = 1; x < n; x++) {
    1081         531 :         SizePair area = areas[(y-1)*matrixWidth+x-1];
    1082         531 :         if (!area.mSize) {
    1083         236 :           area = SizePair::VeryLargeNegative();
    1084             :         }
    1085        1062 :         area = area + pareas[    y*n+x-1]
    1086        1593 :                     + pareas[(y-1)*n+x  ]
    1087        1062 :                     - pareas[(y-1)*n+x-1];
    1088         531 :         pareas[y*n+x] = area;
    1089             :       }
    1090             :     }
    1091             : 
    1092             :     // No longer need the grid
    1093          59 :     areas.SetLength(0);
    1094             : 
    1095          59 :     SizePair bestArea;
    1096             :     struct {
    1097             :       int32_t left, top, right, bottom;
    1098          59 :     } bestRectIndices = { 0, 0, 0, 0 };
    1099         295 :     for (int32_t m1 = 0; m1 < m; m1++) {
    1100         590 :       for (int32_t m2 = m1+1; m2 < m; m2++) {
    1101         708 :         nsTArray<SizePair> B;
    1102         354 :         B.SetLength(n);
    1103        1770 :         for (int32_t i = 0; i < n; i++) {
    1104        1416 :           B[i] = pareas[m2*n+i] - pareas[m1*n+i];
    1105             :         }
    1106             :         int32_t minIdx, maxIdx;
    1107         354 :         SizePair area = MaxSum1D(B, n, &minIdx, &maxIdx);
    1108         354 :         if (area > bestArea) {
    1109         177 :           bestRectIndices.left = minIdx;
    1110         177 :           bestRectIndices.top = m1;
    1111         177 :           bestRectIndices.right = maxIdx;
    1112         177 :           bestRectIndices.bottom = m2;
    1113         177 :           bestArea = area;
    1114             :         }
    1115             :       }
    1116             :     }
    1117             : 
    1118          59 :     bestRect.MoveTo(xaxis.StopAt(bestRectIndices.left),
    1119          59 :                     yaxis.StopAt(bestRectIndices.top));
    1120          59 :     bestRect.SizeTo(xaxis.StopAt(bestRectIndices.right) - bestRect.x,
    1121         118 :                     yaxis.StopAt(bestRectIndices.bottom) - bestRect.y);
    1122             :   }
    1123             : 
    1124          59 :   return bestRect;
    1125             : }
    1126             : 
    1127           0 : std::ostream& operator<<(std::ostream& stream, const nsRegion& m) {
    1128           0 :   stream << "[";
    1129             : 
    1130             :   int n;
    1131           0 :   pixman_box32_t *boxes = pixman_region32_rectangles(const_cast<pixman_region32_t*>(&m.mImpl), &n);
    1132           0 :   for (int i=0; i<n; i++) {
    1133           0 :     if (i != 0) {
    1134           0 :       stream << "; ";
    1135             :     }
    1136           0 :     stream << boxes[i].x1 << "," << boxes[i].y1 << "," << boxes[i].x2 << "," << boxes[i].y2;
    1137             :   }
    1138             : 
    1139           0 :   stream << "]";
    1140           0 :   return stream;
    1141             : }
    1142             : 
    1143             : nsCString
    1144           0 : nsRegion::ToString() const {
    1145           0 :   return nsCString(mozilla::ToString(*this).c_str());
    1146             : }

Generated by: LCOV version 1.13