Back to index

lightning-sunbird  0.9+nobinonly
nsRegionGTK2.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 <gdk/gdkregion.h>
00041 #include "nsRegionGTK.h"
00042 #include "nsMemory.h"
00043 
00044 #ifdef DEBUG_REGIONS
00045 static int nRegions;
00046 #endif
00047 
00048 nsRegionGTK::nsRegionGTK()
00049 {
00050 #ifdef DEBUG_REGIONS
00051   ++nRegions;
00052   printf("REGIONS+ = %i\n", nRegions);
00053 #endif
00054 
00055   mRegion = nsnull;
00056 }
00057 
00058 nsRegionGTK::~nsRegionGTK()
00059 {
00060 #ifdef DEBUG_REGIONS
00061   --nRegions;
00062   printf("REGIONS- = %i\n", nRegions);
00063 #endif
00064 
00065   if (mRegion)
00066     gdk_region_destroy(mRegion);
00067   mRegion = nsnull;
00068 }
00069 
00070 NS_IMPL_ISUPPORTS1(nsRegionGTK, nsIRegion)
00071 
00072 nsresult nsRegionGTK::Init(void)
00073 {
00074   if (mRegion) {
00075     gdk_region_destroy(mRegion);
00076     mRegion = nsnull;
00077   }
00078 
00079   return NS_OK;
00080 }
00081 
00082 void nsRegionGTK::SetTo(const nsIRegion &aRegion)
00083 {
00084   Init();
00085 
00086   nsRegionGTK *pRegion = (nsRegionGTK *)&aRegion;
00087 
00088   mRegion = gdk_region_copy(pRegion->mRegion);
00089 }
00090 
00091 void nsRegionGTK::SetTo(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight)
00092 {
00093   Init();
00094   
00095   GdkRectangle rect;
00096   rect.x = aX;
00097   rect.y = aY;
00098   rect.width = aWidth;
00099   rect.height = aHeight;
00100 
00101   mRegion = gdk_region_rectangle(&rect);
00102 }
00103 
00104 void nsRegionGTK::Intersect(const nsIRegion &aRegion)
00105 {
00106   if(!mRegion) {
00107     NS_WARNING("mRegion is NULL");
00108     return;
00109   }
00110 
00111   nsRegionGTK * pRegion = (nsRegionGTK *)&aRegion;
00112 
00113   gdk_region_intersect(mRegion, pRegion->mRegion);
00114 }
00115 
00116 void nsRegionGTK::Intersect(PRInt32 aX, PRInt32 aY,
00117                             PRInt32 aWidth, PRInt32 aHeight)
00118 {
00119   if(!mRegion) {
00120     NS_WARNING("mRegion is NULL");
00121     return;
00122   }
00123 
00124   GdkRectangle rect;
00125   rect.x = aX;
00126   rect.y = aY;
00127   rect.width = aWidth;
00128   rect.height = aHeight;
00129 
00130   GdkRegion *tRegion = gdk_region_rectangle(&rect);
00131 
00132   gdk_region_intersect(mRegion, tRegion);
00133   gdk_region_destroy(tRegion);
00134 }
00135 
00136 void nsRegionGTK::Union(const nsIRegion &aRegion)
00137 {
00138   nsRegionGTK *pRegion = (nsRegionGTK *)&aRegion;
00139 
00140   if (pRegion->mRegion && !gdk_region_empty(pRegion->mRegion)) {
00141     if (mRegion) {
00142       if (gdk_region_empty(mRegion)) {
00143         gdk_region_destroy(mRegion);
00144         mRegion = gdk_region_copy(pRegion->mRegion);
00145       } else {
00146         gdk_region_union(mRegion, pRegion->mRegion);
00147       }
00148     } else
00149       mRegion = gdk_region_copy(pRegion->mRegion);
00150   }
00151 }
00152 
00153 void nsRegionGTK::Union(PRInt32 aX, PRInt32 aY,
00154                         PRInt32 aWidth, PRInt32 aHeight)
00155 {
00156   GdkRectangle grect;
00157   
00158   grect.x = aX;
00159   grect.y = aY;
00160   grect.width = aWidth;
00161   grect.height = aHeight;
00162   
00163   if (mRegion) {
00164     if (grect.width > 0 && grect.height > 0) {
00165       if (gdk_region_empty(mRegion)) {
00166         gdk_region_destroy(mRegion);
00167         mRegion = gdk_region_rectangle(&grect);
00168       } else {
00169         gdk_region_union_with_rect(mRegion, &grect);
00170       }
00171     }
00172   } else {
00173     mRegion = gdk_region_rectangle(&grect);
00174   }
00175 }
00176 
00177 void nsRegionGTK::Subtract(const nsIRegion &aRegion)
00178 {
00179   nsRegionGTK *pRegion = (nsRegionGTK *)&aRegion;
00180   if (pRegion->mRegion) {
00181     if (mRegion) {
00182       gdk_region_subtract(mRegion, pRegion->mRegion);
00183     } else {
00184       mRegion = gdk_region_new();
00185       gdk_region_subtract(mRegion, pRegion->mRegion);
00186     }
00187   }
00188 }
00189 
00190 void nsRegionGTK::Subtract(PRInt32 aX, PRInt32 aY,
00191                            PRInt32 aWidth, PRInt32 aHeight)
00192 {
00193   GdkRectangle rect;
00194   rect.x = aX;
00195   rect.y = aY;
00196   rect.width = aWidth;
00197   rect.height = aHeight;
00198   GdkRegion *tRegion = gdk_region_rectangle(&rect);
00199 
00200   if (mRegion) {
00201     gdk_region_subtract(mRegion, tRegion);
00202   } else {
00203     NS_WARNING("subtracting from a non-region?");
00204     mRegion = gdk_region_new();
00205     gdk_region_subtract(mRegion, tRegion);
00206   }
00207 
00208   gdk_region_destroy(tRegion);
00209 }
00210 
00211 PRBool nsRegionGTK::IsEmpty(void)
00212 {
00213   if (!mRegion)
00214     return PR_TRUE;
00215   return (gdk_region_empty(mRegion));
00216 }
00217 
00218 PRBool nsRegionGTK::IsEqual(const nsIRegion &aRegion)
00219 {
00220   nsRegionGTK *pRegion = (nsRegionGTK *)&aRegion;
00221 
00222   if (mRegion && pRegion->mRegion) {
00223     return(gdk_region_equal(mRegion, pRegion->mRegion));
00224   } else if (!mRegion && !pRegion->mRegion) {
00225     return PR_TRUE;
00226   } else if ((mRegion && !pRegion->mRegion) || (!mRegion && pRegion->mRegion)) {
00227     return PR_FALSE;
00228   }
00229 
00230   return PR_FALSE;
00231 }
00232 
00233 void nsRegionGTK::GetBoundingBox(PRInt32 *aX, PRInt32 *aY, PRInt32 *aWidth, PRInt32 *aHeight)
00234 {
00235   if (mRegion) {
00236     GdkRectangle rect;
00237 
00238     gdk_region_get_clipbox(mRegion, &rect);
00239 
00240     *aX = rect.x;
00241     *aY = rect.y;
00242     *aWidth = rect.width;
00243     *aHeight = rect.height;
00244   } else {
00245     *aX = 0;
00246     *aY = 0;
00247     *aWidth = 0;
00248     *aHeight = 0;
00249   }
00250 }
00251 
00252 void nsRegionGTK::Offset(PRInt32 aXOffset, PRInt32 aYOffset)
00253 {
00254   if (mRegion) {
00255     gdk_region_offset(mRegion, aXOffset, aYOffset);
00256   }
00257 }
00258 
00259 PRBool nsRegionGTK::ContainsRect(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight)
00260 {
00261   if (mRegion) {
00262     GdkOverlapType containment;
00263     GdkRectangle rect;
00264    
00265     rect.x = aX;
00266     rect.y = aY;
00267     rect.width = aWidth;
00268     rect.height = aHeight;
00269    
00270     containment = gdk_region_rect_in(mRegion, &rect);
00271 
00272     if (containment != GDK_OVERLAP_RECTANGLE_OUT)
00273       return PR_TRUE;
00274   }
00275   return PR_FALSE;
00276 }
00277 
00278 NS_IMETHODIMP nsRegionGTK::GetRects(nsRegionRectSet **aRects)
00279 {
00280   nsRegionRectSet *retval;
00281   nsRegionRect *regionrect;
00282 
00283   *aRects = nsnull;
00284 
00285   if (!mRegion)
00286     return NS_OK;
00287 
00288   GdkRectangle *rects = nsnull;
00289   gint          nrects = 0;
00290   
00291   gdk_region_get_rectangles(mRegion, &rects, &nrects);
00292 
00293   // There are no rectangles in this region but we still need to
00294   // return an empty structure.
00295   if (!nrects) {
00296     retval = (nsRegionRectSet *)nsMemory::Alloc(sizeof(nsRegionRectSet));
00297     if (!retval)
00298       return NS_ERROR_OUT_OF_MEMORY;
00299 
00300     retval->mNumRects = 0;
00301     retval->mRectsLen = 0;
00302     retval->mArea = 0;
00303 
00304     *aRects = retval;
00305 
00306     return NS_OK;
00307   }
00308 
00309   // allocate space for our return values
00310   retval = (nsRegionRectSet *)
00311     nsMemory::Alloc(sizeof(nsRegionRectSet) +
00312                     (sizeof(nsRegionRect) * (nrects - 1)));
00313   if (!retval)
00314     return NS_ERROR_OUT_OF_MEMORY;
00315 
00316   regionrect = &retval->mRects[0];
00317   retval->mNumRects = nrects;
00318   retval->mRectsLen = nrects;
00319 
00320   int currect = 0;
00321   while (currect < nrects) {
00322     regionrect->x = rects[currect].x;
00323     regionrect->y = rects[currect].y;
00324     regionrect->width = rects[currect].width;
00325     regionrect->height = rects[currect].height;
00326 
00327     retval->mArea += rects[currect].width * rects[currect].height;
00328 
00329     currect++;
00330     regionrect++;
00331   }
00332 
00333   // they are allocated as one lump
00334   g_free(rects);
00335 
00336   *aRects = retval;
00337   return NS_OK;
00338 }
00339 
00340 NS_IMETHODIMP nsRegionGTK::FreeRects(nsRegionRectSet *aRects)
00341 {
00342   if (nsnull != aRects)
00343     nsMemory::Free(aRects);
00344 
00345   return NS_OK;
00346 }
00347 
00348 NS_IMETHODIMP nsRegionGTK::GetNativeRegion(void *&aRegion) const
00349 {
00350   aRegion = (void *)mRegion;
00351   return NS_OK;
00352 }
00353 
00354 NS_IMETHODIMP nsRegionGTK::GetRegionComplexity(nsRegionComplexity &aComplexity) const
00355 {
00356   // cast to avoid const-ness problems on some compilers
00357   if (((nsRegionGTK*)this)->IsEmpty())
00358     aComplexity = eRegionComplexity_empty;
00359   else
00360     aComplexity = eRegionComplexity_complex;
00361 
00362   return NS_OK;
00363 }
00364 
00365 NS_IMETHODIMP nsRegionGTK::GetNumRects(PRUint32 *aRects) const
00366 {
00367   if (!mRegion)
00368     *aRects = 0;
00369 
00370   GdkRectangle *rects = nsnull;
00371   gint nrects = 0;
00372 
00373   gdk_region_get_rectangles(mRegion, &rects, &nrects);
00374 
00375   // freed as one lump
00376   g_free(rects);
00377 
00378   *aRects = nrects;
00379   
00380   return NS_OK;
00381 }