Back to index

lightning-sunbird  0.9+nobinonly
nsRegionGTK.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Stuart Parmenter.
00020  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Stuart Parmenter <pavlov@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include <gtk/gtk.h>
00041 #include <gdk/gdkprivate.h>
00042 #include "nsRegionGTK.h"
00043 #include "xregion.h"
00044 #include "prmem.h"
00045 
00046 #ifdef DEBUG_REGIONS
00047 static int nRegions;
00048 #endif
00049 
00050 GdkRegion *nsRegionGTK::copyRegion = nsnull;
00051 
00052 
00053 nsRegionGTK::nsRegionGTK()
00054 {
00055 #ifdef DEBUG_REGIONS
00056   ++nRegions;
00057   printf("REGIONS+ = %i\n", nRegions);
00058 #endif
00059 
00060   mRegion = nsnull;
00061 }
00062 
00063 nsRegionGTK::~nsRegionGTK()
00064 {
00065 #ifdef DEBUG_REGIONS
00066   --nRegions;
00067   printf("REGIONS- = %i\n", nRegions);
00068 #endif
00069 
00070   if (mRegion)
00071     ::gdk_region_destroy(mRegion);
00072   mRegion = nsnull;
00073 }
00074 
00075 NS_IMPL_ISUPPORTS1(nsRegionGTK, nsIRegion)
00076 
00077 
00078 /* static */ void
00079 nsRegionGTK::Shutdown()
00080 {
00081   if (copyRegion) {
00082     gdk_region_destroy(copyRegion);
00083     copyRegion = nsnull;
00084   }
00085 }
00086 
00087 GdkRegion *
00088 nsRegionGTK::GetCopyRegion() {
00089   if (!copyRegion) copyRegion = gdk_region_new();
00090   return copyRegion;
00091 }
00092 
00093 
00094 
00095 GdkRegion *
00096 nsRegionGTK::gdk_region_copy(GdkRegion *region)
00097 {
00098   return gdk_regions_union(region, GetCopyRegion());
00099 }
00100 
00101 GdkRegion *
00102 nsRegionGTK::gdk_region_from_rect(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight)
00103 {
00104   GdkRectangle grect;
00105 
00106   grect.x = aX;
00107   grect.y = aY;
00108   grect.width = aWidth;
00109   grect.height = aHeight;
00110 
00111   return ::gdk_region_union_with_rect(GetCopyRegion(), &grect);
00112 }
00113 
00114 nsresult nsRegionGTK::Init(void)
00115 {
00116   if (mRegion) {
00117     gdk_region_destroy(mRegion);
00118     mRegion = nsnull;
00119   }
00120 
00121   return NS_OK;
00122 }
00123 
00124 void nsRegionGTK::SetTo(const nsIRegion &aRegion)
00125 {
00126   Init();
00127 
00128   nsRegionGTK *pRegion = (nsRegionGTK *)&aRegion;
00129 
00130   mRegion = gdk_region_copy(pRegion->mRegion);
00131 }
00132 
00133 void nsRegionGTK::SetTo(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight)
00134 {
00135   Init();
00136 
00137   mRegion = gdk_region_from_rect(aX, aY, aWidth, aHeight);
00138 }
00139 
00140 void nsRegionGTK::Intersect(const nsIRegion &aRegion)
00141 {
00142   if(!mRegion) {
00143     NS_WARNING("mRegion is NULL");
00144     return;
00145   }
00146 
00147   nsRegionGTK * pRegion = (nsRegionGTK *)&aRegion;
00148 
00149   GdkRegion *nRegion = ::gdk_regions_intersect(mRegion, pRegion->mRegion);
00150   ::gdk_region_destroy(mRegion);
00151   mRegion = nRegion;
00152 }
00153 
00154 void nsRegionGTK::Intersect(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight)
00155 {
00156   if(!mRegion) {
00157     NS_WARNING("mRegion is NULL");
00158     return;
00159   }
00160 
00161   GdkRegion *tRegion = gdk_region_from_rect(aX, aY, aWidth, aHeight);
00162 
00163   GdkRegion *nRegion = ::gdk_regions_intersect(mRegion, tRegion);
00164   ::gdk_region_destroy(tRegion);
00165   ::gdk_region_destroy(mRegion);
00166   mRegion = nRegion;
00167 }
00168 
00169 void nsRegionGTK::Union(const nsIRegion &aRegion)
00170 {
00171   nsRegionGTK *pRegion = (nsRegionGTK *)&aRegion;
00172 
00173   if (pRegion->mRegion && !::gdk_region_empty(pRegion->mRegion)) {
00174     if (mRegion) {
00175       if (::gdk_region_empty(mRegion)) {
00176         ::gdk_region_destroy(mRegion);
00177         mRegion = gdk_region_copy(pRegion->mRegion);
00178       } else {
00179         GdkRegion *nRegion = ::gdk_regions_union(mRegion, pRegion->mRegion);
00180         ::gdk_region_destroy(mRegion);
00181         mRegion = nRegion;
00182       }
00183     } else
00184       mRegion = gdk_region_copy(pRegion->mRegion);
00185   }
00186 }
00187 
00188 void nsRegionGTK::Union(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight)
00189 {
00190   if (mRegion) {
00191     GdkRectangle grect;
00192 
00193     grect.x = aX;
00194     grect.y = aY;
00195     grect.width = aWidth;
00196     grect.height = aHeight;
00197 
00198     if (grect.width > 0 && grect.height > 0) {
00199       if (::gdk_region_empty(mRegion)) {
00200         ::gdk_region_destroy(mRegion);
00201         mRegion = gdk_region_from_rect(aX, aY, aWidth, aHeight);
00202       } else {
00203         GdkRegion *nRegion = ::gdk_region_union_with_rect(mRegion, &grect);
00204         ::gdk_region_destroy(mRegion);
00205         mRegion = nRegion;
00206       }
00207     }
00208   } else {
00209     mRegion = gdk_region_from_rect(aX, aY, aWidth, aHeight);
00210   }
00211 }
00212 
00213 void nsRegionGTK::Subtract(const nsIRegion &aRegion)
00214 {
00215   nsRegionGTK *pRegion = (nsRegionGTK *)&aRegion;
00216   if (pRegion->mRegion) {
00217     if (mRegion) {
00218       GdkRegion *nRegion = ::gdk_regions_subtract(mRegion, pRegion->mRegion);
00219       ::gdk_region_destroy(mRegion);
00220       mRegion = nRegion;
00221     } else {
00222       mRegion = ::gdk_regions_subtract(GetCopyRegion(), pRegion->mRegion);
00223     }
00224   }
00225 }
00226 
00227 void nsRegionGTK::Subtract(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight)
00228 {
00229   if (mRegion) {
00230     GdkRegion *tRegion = gdk_region_from_rect(aX, aY, aWidth, aHeight);
00231     
00232     GdkRegion *nRegion = ::gdk_regions_subtract(mRegion, tRegion);
00233     ::gdk_region_destroy(mRegion);
00234     ::gdk_region_destroy(tRegion);
00235     mRegion = nRegion;
00236   } else {
00237     GdkRegion *tRegion = gdk_region_from_rect(aX, aY, aWidth, aHeight);
00238     mRegion = ::gdk_regions_subtract(GetCopyRegion(), tRegion);
00239     ::gdk_region_destroy(tRegion);
00240   }
00241 }
00242 
00243 PRBool nsRegionGTK::IsEmpty(void)
00244 {
00245   if (!mRegion)
00246     return PR_TRUE;
00247   return (::gdk_region_empty(mRegion));
00248 }
00249 
00250 PRBool nsRegionGTK::IsEqual(const nsIRegion &aRegion)
00251 {
00252   nsRegionGTK *pRegion = (nsRegionGTK *)&aRegion;
00253 
00254   if (mRegion && pRegion->mRegion) {
00255     return(::gdk_region_equal(mRegion, pRegion->mRegion));
00256   } else if (!mRegion && !pRegion->mRegion) {
00257     return PR_TRUE;
00258   } else if ((mRegion && !pRegion->mRegion) || (!mRegion && pRegion->mRegion)) {
00259     return PR_FALSE;
00260   }
00261 
00262   return PR_FALSE;
00263 }
00264 
00265 void nsRegionGTK::GetBoundingBox(PRInt32 *aX, PRInt32 *aY, PRInt32 *aWidth, PRInt32 *aHeight)
00266 {
00267   if (mRegion) {
00268     GdkRectangle rect;
00269 
00270     ::gdk_region_get_clipbox(mRegion, &rect);
00271 
00272     *aX = rect.x;
00273     *aY = rect.y;
00274     *aWidth = rect.width;
00275     *aHeight = rect.height;
00276   } else {
00277     *aX = 0;
00278     *aY = 0;
00279     *aWidth = 0;
00280     *aHeight = 0;
00281   }
00282 }
00283 
00284 void nsRegionGTK::Offset(PRInt32 aXOffset, PRInt32 aYOffset)
00285 {
00286   if (mRegion) {
00287     ::gdk_region_offset(mRegion, aXOffset, aYOffset);
00288   }
00289 }
00290 
00291 PRBool nsRegionGTK::ContainsRect(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight)
00292 {
00293   if (mRegion) {
00294     GdkOverlapType containment;
00295     GdkRectangle rect;
00296    
00297     rect.x = aX;
00298     rect.y = aY;
00299     rect.width = aWidth;
00300     rect.height = aHeight;
00301    
00302     containment = ::gdk_region_rect_in(mRegion, &rect);
00303 
00304     if (containment != GDK_OVERLAP_RECTANGLE_OUT)
00305       return PR_TRUE;
00306   }
00307   return PR_FALSE;
00308 }
00309 
00310 NS_IMETHODIMP nsRegionGTK::GetRects(nsRegionRectSet **aRects)
00311 {
00312 
00313   *aRects = nsnull;
00314 
00315   if (!mRegion)
00316     return NS_OK;
00317 
00318   nsRegionRectSet   *rects = nsnull;
00319   GdkRegionPrivate  *priv = nsnull;
00320   Region            pRegion;
00321   int               nbox = 0;
00322   BOX               *pbox = nsnull;
00323   nsRegionRect      *rect = nsnull;
00324 
00325   priv = (GdkRegionPrivate *)mRegion;
00326   pRegion = priv->xregion;
00327   pbox = pRegion->rects;
00328   nbox = pRegion->numRects;
00329 
00330   NS_ASSERTION(!(nsnull == aRects), "bad ptr");
00331 
00332   //code lifted from old xfe. MMP
00333 
00334   rects = *aRects;
00335 
00336   if ((nsnull == rects) || (rects->mRectsLen < (PRUint32)nbox))
00337   {
00338     void *buf = PR_Realloc(rects, sizeof(nsRegionRectSet) + (sizeof(nsRegionRect) * (nbox - 1)));
00339 
00340     if (nsnull == buf)
00341     {
00342       if (nsnull != rects)
00343         rects->mNumRects = 0;
00344 
00345       return NS_OK;
00346     }
00347 
00348     rects = (nsRegionRectSet *)buf;
00349     rects->mRectsLen = nbox;
00350   }
00351 
00352   rects->mNumRects = nbox;
00353   rects->mArea = 0;
00354   rect = &rects->mRects[0];
00355 
00356   while (nbox--)
00357   {
00358     rect->x = pbox->x1;
00359     rect->width = (pbox->x2 - pbox->x1);
00360     rect->y = pbox->y1;
00361     rect->height = (pbox->y2 - pbox->y1);
00362 
00363     rects->mArea += rect->width * rect->height;
00364 
00365     pbox++;
00366     rect++;
00367   }
00368 
00369   *aRects = rects;
00370 
00371   return NS_OK;
00372 }
00373 
00374 NS_IMETHODIMP nsRegionGTK::FreeRects(nsRegionRectSet *aRects)
00375 {
00376   if (nsnull != aRects)
00377     PR_Free((void *)aRects);
00378 
00379   return NS_OK;
00380 }
00381 
00382 NS_IMETHODIMP nsRegionGTK::GetNativeRegion(void *&aRegion) const
00383 {
00384   aRegion = (void *)mRegion;
00385   return NS_OK;
00386 }
00387 
00388 NS_IMETHODIMP nsRegionGTK::GetRegionComplexity(nsRegionComplexity &aComplexity) const
00389 {
00390   // cast to avoid const-ness problems on some compilers
00391   if (((nsRegionGTK*)this)->IsEmpty())
00392     aComplexity = eRegionComplexity_empty;
00393   else
00394     aComplexity = eRegionComplexity_complex;
00395 
00396   return NS_OK;
00397 }
00398 
00399 void nsRegionGTK::SetRegionEmpty()
00400 {
00401   if (!IsEmpty()) {
00402     ::gdk_region_destroy(mRegion);
00403   }
00404 }
00405 
00406 NS_IMETHODIMP nsRegionGTK::GetNumRects(PRUint32 *aRects) const
00407 {
00408   if (!mRegion)
00409     *aRects = 0;
00410 
00411   GdkRegionPrivate  *priv = (GdkRegionPrivate *)mRegion;
00412   Region pRegion = priv->xregion;
00413 
00414   *aRects = pRegion->numRects;
00415 
00416   return NS_OK;
00417 }