1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/src/nsRect.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,317 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 + 1.10 +#ifndef NSRECT_H 1.11 +#define NSRECT_H 1.12 + 1.13 +#include <stdio.h> // for FILE 1.14 +#include <stdint.h> // for int32_t, int64_t 1.15 +#include <algorithm> // for min/max 1.16 +#include "nsDebug.h" // for NS_WARNING 1.17 +#include "gfxCore.h" // for NS_GFX 1.18 +#include "mozilla/Likely.h" // for MOZ_UNLIKELY 1.19 +#include "mozilla/gfx/BaseRect.h" // for BaseRect 1.20 +#include "nsCoord.h" // for nscoord, etc 1.21 +#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc 1.22 +#include "nsPoint.h" // for nsIntPoint, nsPoint 1.23 +#include "nsSize.h" // for nsIntSize, nsSize 1.24 +#include "nscore.h" // for NS_BUILD_REFCNT_LOGGING 1.25 + 1.26 +struct nsIntRect; 1.27 +struct nsMargin; 1.28 +struct nsIntMargin; 1.29 + 1.30 +struct NS_GFX nsRect : 1.31 + public mozilla::gfx::BaseRect<nscoord, nsRect, nsPoint, nsSize, nsMargin> { 1.32 + typedef mozilla::gfx::BaseRect<nscoord, nsRect, nsPoint, nsSize, nsMargin> Super; 1.33 + 1.34 + static void VERIFY_COORD(nscoord aValue) { ::VERIFY_COORD(aValue); } 1.35 + 1.36 + // Constructors 1.37 + nsRect() : Super() 1.38 + { 1.39 + MOZ_COUNT_CTOR(nsRect); 1.40 + } 1.41 + nsRect(const nsRect& aRect) : Super(aRect) 1.42 + { 1.43 + MOZ_COUNT_CTOR(nsRect); 1.44 + } 1.45 + nsRect(const nsPoint& aOrigin, const nsSize &aSize) : Super(aOrigin, aSize) 1.46 + { 1.47 + MOZ_COUNT_CTOR(nsRect); 1.48 + } 1.49 + nsRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) : 1.50 + Super(aX, aY, aWidth, aHeight) 1.51 + { 1.52 + MOZ_COUNT_CTOR(nsRect); 1.53 + } 1.54 + 1.55 +#ifdef NS_BUILD_REFCNT_LOGGING 1.56 + ~nsRect() { 1.57 + MOZ_COUNT_DTOR(nsRect); 1.58 + } 1.59 +#endif 1.60 + 1.61 + // We have saturating versions of all the Union methods. These avoid 1.62 + // overflowing nscoord values in the 'width' and 'height' fields by 1.63 + // clamping the width and height values to nscoord_MAX if necessary. 1.64 + 1.65 + nsRect SaturatingUnion(const nsRect& aRect) const 1.66 + { 1.67 + if (IsEmpty()) { 1.68 + return aRect; 1.69 + } else if (aRect.IsEmpty()) { 1.70 + return *static_cast<const nsRect*>(this); 1.71 + } else { 1.72 + return SaturatingUnionEdges(aRect); 1.73 + } 1.74 + } 1.75 + 1.76 + nsRect SaturatingUnionEdges(const nsRect& aRect) const 1.77 + { 1.78 +#ifdef NS_COORD_IS_FLOAT 1.79 + return UnionEdges(aRect); 1.80 +#else 1.81 + nsRect result; 1.82 + result.x = std::min(aRect.x, x); 1.83 + int64_t w = std::max(int64_t(aRect.x) + aRect.width, int64_t(x) + width) - result.x; 1.84 + if (MOZ_UNLIKELY(w > nscoord_MAX)) { 1.85 + NS_WARNING("Overflowed nscoord_MAX in conversion to nscoord width"); 1.86 + // Clamp huge negative x to nscoord_MIN / 2 and try again. 1.87 + result.x = std::max(result.x, nscoord_MIN / 2); 1.88 + w = std::max(int64_t(aRect.x) + aRect.width, int64_t(x) + width) - result.x; 1.89 + if (MOZ_UNLIKELY(w > nscoord_MAX)) { 1.90 + w = nscoord_MAX; 1.91 + } 1.92 + } 1.93 + result.width = nscoord(w); 1.94 + 1.95 + result.y = std::min(aRect.y, y); 1.96 + int64_t h = std::max(int64_t(aRect.y) + aRect.height, int64_t(y) + height) - result.y; 1.97 + if (MOZ_UNLIKELY(h > nscoord_MAX)) { 1.98 + NS_WARNING("Overflowed nscoord_MAX in conversion to nscoord height"); 1.99 + // Clamp huge negative y to nscoord_MIN / 2 and try again. 1.100 + result.y = std::max(result.y, nscoord_MIN / 2); 1.101 + h = std::max(int64_t(aRect.y) + aRect.height, int64_t(y) + height) - result.y; 1.102 + if (MOZ_UNLIKELY(h > nscoord_MAX)) { 1.103 + h = nscoord_MAX; 1.104 + } 1.105 + } 1.106 + result.height = nscoord(h); 1.107 + return result; 1.108 +#endif 1.109 + } 1.110 + 1.111 +#ifndef NS_COORD_IS_FLOAT 1.112 + // Make all nsRect Union methods be saturating. 1.113 + nsRect UnionEdges(const nsRect& aRect) const 1.114 + { 1.115 + return SaturatingUnionEdges(aRect); 1.116 + } 1.117 + void UnionRectEdges(const nsRect& aRect1, const nsRect& aRect2) 1.118 + { 1.119 + *this = aRect1.UnionEdges(aRect2); 1.120 + } 1.121 + nsRect Union(const nsRect& aRect) const 1.122 + { 1.123 + return SaturatingUnion(aRect); 1.124 + } 1.125 + void UnionRect(const nsRect& aRect1, const nsRect& aRect2) 1.126 + { 1.127 + *this = aRect1.Union(aRect2); 1.128 + } 1.129 +#endif 1.130 + 1.131 + void SaturatingUnionRect(const nsRect& aRect1, const nsRect& aRect2) 1.132 + { 1.133 + *this = aRect1.SaturatingUnion(aRect2); 1.134 + } 1.135 + void SaturatingUnionRectEdges(const nsRect& aRect1, const nsRect& aRect2) 1.136 + { 1.137 + *this = aRect1.SaturatingUnionEdges(aRect2); 1.138 + } 1.139 + 1.140 + // Converts this rect from aFromAPP, an appunits per pixel ratio, to aToAPP. 1.141 + // In the RoundOut version we make the rect the smallest rect containing the 1.142 + // unrounded result. In the RoundIn version we make the rect the largest rect 1.143 + // contained in the unrounded result. 1.144 + // Note: this can turn an empty rectangle into a non-empty rectangle 1.145 + inline nsRect ConvertAppUnitsRoundOut(int32_t aFromAPP, int32_t aToAPP) const; 1.146 + inline nsRect ConvertAppUnitsRoundIn(int32_t aFromAPP, int32_t aToAPP) const; 1.147 + 1.148 + inline nsIntRect ScaleToNearestPixels(float aXScale, float aYScale, 1.149 + nscoord aAppUnitsPerPixel) const; 1.150 + inline nsIntRect ToNearestPixels(nscoord aAppUnitsPerPixel) const; 1.151 + // Note: this can turn an empty rectangle into a non-empty rectangle 1.152 + inline nsIntRect ScaleToOutsidePixels(float aXScale, float aYScale, 1.153 + nscoord aAppUnitsPerPixel) const; 1.154 + // Note: this can turn an empty rectangle into a non-empty rectangle 1.155 + inline nsIntRect ToOutsidePixels(nscoord aAppUnitsPerPixel) const; 1.156 + inline nsIntRect ScaleToInsidePixels(float aXScale, float aYScale, 1.157 + nscoord aAppUnitsPerPixel) const; 1.158 + inline nsIntRect ToInsidePixels(nscoord aAppUnitsPerPixel) const; 1.159 + 1.160 + // This is here only to keep IPDL-generated code happy. DO NOT USE. 1.161 + bool operator==(const nsRect& aRect) const 1.162 + { 1.163 + return IsEqualEdges(aRect); 1.164 + } 1.165 +}; 1.166 + 1.167 +struct NS_GFX nsIntRect : 1.168 + public mozilla::gfx::BaseRect<int32_t, nsIntRect, nsIntPoint, nsIntSize, nsIntMargin> { 1.169 + typedef mozilla::gfx::BaseRect<int32_t, nsIntRect, nsIntPoint, nsIntSize, nsIntMargin> Super; 1.170 + 1.171 + // Constructors 1.172 + nsIntRect() : Super() 1.173 + { 1.174 + } 1.175 + nsIntRect(const nsIntRect& aRect) : Super(aRect) 1.176 + { 1.177 + } 1.178 + nsIntRect(const nsIntPoint& aOrigin, const nsIntSize &aSize) : Super(aOrigin, aSize) 1.179 + { 1.180 + } 1.181 + nsIntRect(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight) : 1.182 + Super(aX, aY, aWidth, aHeight) 1.183 + { 1.184 + } 1.185 + 1.186 + inline nsRect ToAppUnits(nscoord aAppUnitsPerPixel) const; 1.187 + 1.188 + // Returns a special nsIntRect that's used in some places to signify 1.189 + // "all available space". 1.190 + static const nsIntRect& GetMaxSizedIntRect() { 1.191 + static const nsIntRect r(0, 0, INT32_MAX, INT32_MAX); 1.192 + return r; 1.193 + } 1.194 + 1.195 + // This is here only to keep IPDL-generated code happy. DO NOT USE. 1.196 + bool operator==(const nsIntRect& aRect) const 1.197 + { 1.198 + return IsEqualEdges(aRect); 1.199 + } 1.200 +}; 1.201 + 1.202 +/* 1.203 + * App Unit/Pixel conversions 1.204 + */ 1.205 + 1.206 +inline nsRect 1.207 +nsRect::ConvertAppUnitsRoundOut(int32_t aFromAPP, int32_t aToAPP) const 1.208 +{ 1.209 + if (aFromAPP == aToAPP) { 1.210 + return *this; 1.211 + } 1.212 + 1.213 + nsRect rect; 1.214 + nscoord right = NSToCoordCeil(NSCoordScale(XMost(), aFromAPP, aToAPP)); 1.215 + nscoord bottom = NSToCoordCeil(NSCoordScale(YMost(), aFromAPP, aToAPP)); 1.216 + rect.x = NSToCoordFloor(NSCoordScale(x, aFromAPP, aToAPP)); 1.217 + rect.y = NSToCoordFloor(NSCoordScale(y, aFromAPP, aToAPP)); 1.218 + rect.width = (right - rect.x); 1.219 + rect.height = (bottom - rect.y); 1.220 + 1.221 + return rect; 1.222 +} 1.223 + 1.224 +inline nsRect 1.225 +nsRect::ConvertAppUnitsRoundIn(int32_t aFromAPP, int32_t aToAPP) const 1.226 +{ 1.227 + if (aFromAPP == aToAPP) { 1.228 + return *this; 1.229 + } 1.230 + 1.231 + nsRect rect; 1.232 + nscoord right = NSToCoordFloor(NSCoordScale(XMost(), aFromAPP, aToAPP)); 1.233 + nscoord bottom = NSToCoordFloor(NSCoordScale(YMost(), aFromAPP, aToAPP)); 1.234 + rect.x = NSToCoordCeil(NSCoordScale(x, aFromAPP, aToAPP)); 1.235 + rect.y = NSToCoordCeil(NSCoordScale(y, aFromAPP, aToAPP)); 1.236 + rect.width = (right - rect.x); 1.237 + rect.height = (bottom - rect.y); 1.238 + 1.239 + return rect; 1.240 +} 1.241 + 1.242 +// scale the rect but round to preserve centers 1.243 +inline nsIntRect 1.244 +nsRect::ScaleToNearestPixels(float aXScale, float aYScale, 1.245 + nscoord aAppUnitsPerPixel) const 1.246 +{ 1.247 + nsIntRect rect; 1.248 + rect.x = NSToIntRoundUp(NSAppUnitsToDoublePixels(x, aAppUnitsPerPixel) * aXScale); 1.249 + rect.y = NSToIntRoundUp(NSAppUnitsToDoublePixels(y, aAppUnitsPerPixel) * aYScale); 1.250 + rect.width = NSToIntRoundUp(NSAppUnitsToDoublePixels(XMost(), 1.251 + aAppUnitsPerPixel) * aXScale) - rect.x; 1.252 + rect.height = NSToIntRoundUp(NSAppUnitsToDoublePixels(YMost(), 1.253 + aAppUnitsPerPixel) * aYScale) - rect.y; 1.254 + return rect; 1.255 +} 1.256 + 1.257 +// scale the rect but round to smallest containing rect 1.258 +inline nsIntRect 1.259 +nsRect::ScaleToOutsidePixels(float aXScale, float aYScale, 1.260 + nscoord aAppUnitsPerPixel) const 1.261 +{ 1.262 + nsIntRect rect; 1.263 + rect.x = NSToIntFloor(NSAppUnitsToFloatPixels(x, float(aAppUnitsPerPixel)) * aXScale); 1.264 + rect.y = NSToIntFloor(NSAppUnitsToFloatPixels(y, float(aAppUnitsPerPixel)) * aYScale); 1.265 + rect.width = NSToIntCeil(NSAppUnitsToFloatPixels(XMost(), 1.266 + float(aAppUnitsPerPixel)) * aXScale) - rect.x; 1.267 + rect.height = NSToIntCeil(NSAppUnitsToFloatPixels(YMost(), 1.268 + float(aAppUnitsPerPixel)) * aYScale) - rect.y; 1.269 + return rect; 1.270 +} 1.271 + 1.272 +// scale the rect but round to largest contained rect 1.273 +inline nsIntRect 1.274 +nsRect::ScaleToInsidePixels(float aXScale, float aYScale, 1.275 + nscoord aAppUnitsPerPixel) const 1.276 +{ 1.277 + nsIntRect rect; 1.278 + rect.x = NSToIntCeil(NSAppUnitsToFloatPixels(x, float(aAppUnitsPerPixel)) * aXScale); 1.279 + rect.y = NSToIntCeil(NSAppUnitsToFloatPixels(y, float(aAppUnitsPerPixel)) * aYScale); 1.280 + rect.width = NSToIntFloor(NSAppUnitsToFloatPixels(XMost(), 1.281 + float(aAppUnitsPerPixel)) * aXScale) - rect.x; 1.282 + rect.height = NSToIntFloor(NSAppUnitsToFloatPixels(YMost(), 1.283 + float(aAppUnitsPerPixel)) * aYScale) - rect.y; 1.284 + return rect; 1.285 +} 1.286 + 1.287 +inline nsIntRect 1.288 +nsRect::ToNearestPixels(nscoord aAppUnitsPerPixel) const 1.289 +{ 1.290 + return ScaleToNearestPixels(1.0f, 1.0f, aAppUnitsPerPixel); 1.291 +} 1.292 + 1.293 +inline nsIntRect 1.294 +nsRect::ToOutsidePixels(nscoord aAppUnitsPerPixel) const 1.295 +{ 1.296 + return ScaleToOutsidePixels(1.0f, 1.0f, aAppUnitsPerPixel); 1.297 +} 1.298 + 1.299 +inline nsIntRect 1.300 +nsRect::ToInsidePixels(nscoord aAppUnitsPerPixel) const 1.301 +{ 1.302 + return ScaleToInsidePixels(1.0f, 1.0f, aAppUnitsPerPixel); 1.303 +} 1.304 + 1.305 +// app units are integer multiples of pixels, so no rounding needed 1.306 +inline nsRect 1.307 +nsIntRect::ToAppUnits(nscoord aAppUnitsPerPixel) const 1.308 +{ 1.309 + return nsRect(NSIntPixelsToAppUnits(x, aAppUnitsPerPixel), 1.310 + NSIntPixelsToAppUnits(y, aAppUnitsPerPixel), 1.311 + NSIntPixelsToAppUnits(width, aAppUnitsPerPixel), 1.312 + NSIntPixelsToAppUnits(height, aAppUnitsPerPixel)); 1.313 +} 1.314 + 1.315 +#ifdef DEBUG 1.316 +// Diagnostics 1.317 +extern NS_GFX FILE* operator<<(FILE* out, const nsRect& rect); 1.318 +#endif // DEBUG 1.319 + 1.320 +#endif /* NSRECT_H */