Backout bug 845874 to clear Holly perma-orange on Windows debug (bug 942250). r=bustage-fix.
authorJoe Drew <joe@drew.ca>
Thu, 05 Dec 2013 18:08:43 -0500
changeset 174577 9e7f91032d7dbf79ea3ea1891473f7a5db96ae03
parent 174576 058506a5ff78dbdc43312aea48755b0101787ff7
child 174637 8882f647856901a4c4b24a0d4b1256738859d277
push id445
push userffxbld
push dateMon, 10 Mar 2014 22:05:19 +0000
treeherdermozilla-release@dc38b741b04e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbustage-fix
bugs845874, 942250
milestone28.0a1
Backout bug 845874 to clear Holly perma-orange on Windows debug (bug 942250). r=bustage-fix.
gfx/cairo/cairo/src/cairo-rename.h
gfx/cairo/cairo/src/moz.build
gfx/cairo/cairo/src/pixman-rename.h
gfx/cairo/libpixman/src/pixman-compiler.h
gfx/cairo/libpixman/src/pixman.h
gfx/src/nsRegion.cpp
gfx/src/nsRegion.h
gfx/tests/gtest/TestRegion.cpp
layout/media/symbols.def.in
uriloader/exthandler/Makefile.in
--- a/gfx/cairo/cairo/src/cairo-rename.h
+++ b/gfx/cairo/cairo/src/cairo-rename.h
@@ -357,9 +357,135 @@
 #define cairo_xlib_surface_get_drawable _moz_cairo_xlib_surface_get_drawable
 #define cairo_xlib_surface_get_height _moz_cairo_xlib_surface_get_height
 #define cairo_xlib_surface_get_screen _moz_cairo_xlib_surface_get_screen
 #define cairo_xlib_surface_get_visual _moz_cairo_xlib_surface_get_visual
 #define cairo_xlib_surface_get_width _moz_cairo_xlib_surface_get_width
 #define cairo_xlib_surface_get_xrender_format _moz_cairo_xlib_surface_get_xrender_format
 #define cairo_xlib_surface_set_drawable _moz_cairo_xlib_surface_set_drawable
 #define cairo_xlib_surface_set_size _moz_cairo_xlib_surface_set_size
-#include "pixman-rename.h"
+#ifdef MOZ_TREE_PIXMAN
+#define pixman_region_set_static_pointers _moz_pixman_region_set_static_pointers
+#define pixman_region_init _moz_pixman_region_init
+#define pixman_region_init_rect _moz_pixman_region_init_rect
+#define pixman_region_init_rects _moz_pixman_region_init_rects
+#define pixman_region_init_with_extents _moz_pixman_region_init_with_extents
+#define pixman_region_fini _moz_pixman_region_fini
+#define pixman_region_translate _moz_pixman_region_translate
+#define pixman_region_copy _moz_pixman_region_copy
+#define pixman_region_intersect _moz_pixman_region_intersect
+#define pixman_region_union _moz_pixman_region_union
+#define pixman_region_union_rect _moz_pixman_region_union_rect
+#define pixman_region_subtract _moz_pixman_region_subtract
+#define pixman_region_inverse _moz_pixman_region_inverse
+#define pixman_region_contains_point _moz_pixman_region_contains_point
+#define pixman_region_contains_rectangle _moz_pixman_region_contains_rectangle
+#define pixman_region_not_empty _moz_pixman_region_not_empty
+#define pixman_region_extents _moz_pixman_region_extents
+#define pixman_region_n_rects _moz_pixman_region_n_rects
+#define pixman_region_rectangles _moz_pixman_region_rectangles
+#define pixman_region_equal _moz_pixman_region_equal
+#define pixman_region_selfcheck _moz_pixman_region_selfcheck
+#define pixman_region_reset _moz_pixman_region_reset
+#define pixman_region32_init _moz_pixman_region32_init
+#define pixman_region32_init_rect _moz_pixman_region32_init_rect
+#define pixman_region32_init_rects _moz_pixman_region32_init_rects
+#define pixman_region32_init_with_extents _moz_pixman_region32_init_with_extents
+#define pixman_region32_fini _moz_pixman_region32_fini
+#define pixman_region32_translate _moz_pixman_region32_translate
+#define pixman_region32_copy _moz_pixman_region32_copy
+#define pixman_region32_intersect _moz_pixman_region32_intersect
+#define pixman_region32_union _moz_pixman_region32_union
+#define pixman_region32_union_rect _moz_pixman_region32_union_rect
+#define pixman_region32_subtract _moz_pixman_region32_subtract
+#define pixman_region32_inverse _moz_pixman_region32_inverse
+#define pixman_region32_contains_point _moz_pixman_region32_contains_point
+#define pixman_region32_contains_rectangle _moz_pixman_region32_contains_rectangle
+#define pixman_region32_not_empty _moz_pixman_region32_not_empty
+#define pixman_region32_extents _moz_pixman_region32_extents
+#define pixman_region32_n_rects _moz_pixman_region32_n_rects
+#define pixman_region32_rectangles _moz_pixman_region32_rectangles
+#define pixman_region32_equal _moz_pixman_region32_equal
+#define pixman_region32_selfcheck _moz_pixman_region32_selfcheck
+#define pixman_region32_reset _moz_pixman_region32_reset
+#define pixman_blt _moz_pixman_blt
+#define pixman_fill _moz_pixman_fill
+#define pixman_transform_point_3d _moz_pixman_transform_point_3d
+#define pixman_version _moz_pixman_version
+#define pixman_version_string _moz_pixman_version_string
+#define pixman_format_supported_destination _moz_pixman_format_supported_destination
+#define pixman_format_supported_source _moz_pixman_format_supported_source
+#define pixman_image_create_solid_fill _moz_pixman_image_create_solid_fill
+#define pixman_image_create_linear_gradient _moz_pixman_image_create_linear_gradient
+#define pixman_image_create_radial_gradient _moz_pixman_image_create_radial_gradient
+#define pixman_image_create_conical_gradient _moz_pixman_image_create_conical_gradient
+#define pixman_image_create_bits _moz_pixman_image_create_bits
+#define pixman_image_ref _moz_pixman_image_ref
+#define pixman_image_unref _moz_pixman_image_unref
+#define pixman_image_set_clip_region _moz_pixman_image_set_clip_region
+#define pixman_image_set_clip_region32 _moz_pixman_image_set_clip_region32
+#define pixman_image_set_has_client_clip _moz_pixman_image_set_has_client_clip
+#define pixman_image_set_transform _moz_pixman_image_set_transform
+#define pixman_image_set_repeat _moz_pixman_image_set_repeat
+#define pixman_image_set_filter _moz_pixman_image_set_filter
+#define pixman_image_set_source_clipping _moz_pixman_image_set_source_clipping
+#define pixman_image_set_alpha_map _moz_pixman_image_set_alpha_map
+#define pixman_image_set_component_alpha _moz_pixman_image_set_component_alpha
+#define pixman_image_set_accessors	 _moz_pixman_image_set_accessors	
+#define pixman_image_set_indexed	 _moz_pixman_image_set_indexed	
+#define pixman_image_get_data _moz_pixman_image_get_data
+#define pixman_image_get_width _moz_pixman_image_get_width
+#define pixman_image_get_height _moz_pixman_image_get_height
+#define pixman_image_get_stride _moz_pixman_image_get_stride
+#define pixman_image_get_depth _moz_pixman_image_get_depth
+#define pixman_image_fill_rectangles	 _moz_pixman_image_fill_rectangles	
+#define pixman_compute_composite_region _moz_pixman_compute_composite_region
+#define pixman_image_composite _moz_pixman_image_composite
+#define pixman_sample_ceil_y _moz_pixman_sample_ceil_y
+#define pixman_sample_floor_y _moz_pixman_sample_floor_y
+#define pixman_edge_step _moz_pixman_edge_step
+#define pixman_edge_init _moz_pixman_edge_init
+#define pixman_line_fixed_edge_init _moz_pixman_line_fixed_edge_init
+#define pixman_rasterize_edges _moz_pixman_rasterize_edges
+#define pixman_add_traps _moz_pixman_add_traps
+#define pixman_add_trapezoids _moz_pixman_add_trapezoids
+#define pixman_rasterize_trapezoid _moz_pixman_rasterize_trapezoid
+#define pixman_disable_out_of_bounds_workaround _moz_pixman_disable_out_of_bounds_workaround
+#define pixman_f_transform_bounds _moz_pixman_f_transform_bounds
+#define pixman_f_transform_from_pixman_transform _moz_pixman_f_transform_from_pixman_transform
+#define pixman_f_transform_init_identity _moz_pixman_f_transform_init_identity
+#define pixman_f_transform_init_rotate _moz_pixman_f_transform_init_rotate
+#define pixman_f_transform_init_scale _moz_pixman_f_transform_init_scale
+#define pixman_f_transform_init_translate _moz_pixman_f_transform_init_translate
+#define pixman_f_transform_invert _moz_pixman_f_transform_invert
+#define pixman_f_transform_multiply _moz_pixman_f_transform_multiply
+#define pixman_f_transform_point _moz_pixman_f_transform_point
+#define pixman_f_transform_point_3d _moz_pixman_f_transform_point_3d
+#define pixman_f_transform_rotate _moz_pixman_f_transform_rotate
+#define pixman_f_transform_scale _moz_pixman_f_transform_scale
+#define pixman_f_transform_translate _moz_pixman_f_transform_translate
+#define pixman_image_composite32 _moz_pixman_image_composite32
+#define pixman_image_fill_boxes _moz_pixman_image_fill_boxes
+#define pixman_image_get_component_alpha _moz_pixman_image_get_component_alpha
+#define pixman_image_get_destroy_data _moz_pixman_image_get_destroy_data
+#define pixman_image_get_format _moz_pixman_image_get_format
+#define pixman_image_set_destroy_function _moz_pixman_image_set_destroy_function
+#define pixman_region_init_from_image _moz_pixman_region_init_from_image
+#define pixman_region_intersect_rect _moz_pixman_region_intersect_rect
+#define pixman_region32_init_from_image _moz_pixman_region32_init_from_image
+#define pixman_region32_intersect_rect _moz_pixman_region32_intersect_rect
+#define pixman_transform_bounds _moz_pixman_transform_bounds
+#define pixman_transform_from_pixman_f_transform _moz_pixman_transform_from_pixman_f_transform
+#define pixman_transform_init_identity _moz_pixman_transform_init_identity
+#define pixman_transform_init_rotate _moz_pixman_transform_init_rotate
+#define pixman_transform_init_scale _moz_pixman_transform_init_scale
+#define pixman_transform_init_translate _moz_pixman_transform_init_translate
+#define pixman_transform_invert _moz_pixman_transform_invert
+#define pixman_transform_is_identity _moz_pixman_transform_is_identity
+#define pixman_transform_is_int_translate _moz_pixman_transform_is_int_translate
+#define pixman_transform_is_inverse _moz_pixman_transform_is_inverse
+#define pixman_transform_is_scale _moz_pixman_transform_is_scale
+#define pixman_transform_multiply _moz_pixman_transform_multiply
+#define pixman_transform_point _moz_pixman_transform_point
+#define pixman_transform_rotate _moz_pixman_transform_rotate
+#define pixman_transform_scale _moz_pixman_transform_scale
+#define pixman_transform_translate _moz_pixman_transform_translate
+#endif
--- a/gfx/cairo/cairo/src/moz.build
+++ b/gfx/cairo/cairo/src/moz.build
@@ -8,17 +8,16 @@ CONFIGURE_SUBST_FILES += ['cairo-feature
 
 EXPORTS.cairo += [
     'cairo-deprecated.h',
     'cairo-platform.h',
     'cairo-rename.h',
     'cairo-tee.h',
     'cairo-version.h',
     'cairo.h',
-    'pixman-rename.h',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] not in ('cocoa', 'uikit'):
     EXPORTS.cairo += [
         'cairo-pdf.h',
     ]
     SOURCES += [
         'cairo-base85-stream.c',
deleted file mode 100644
--- a/gfx/cairo/cairo/src/pixman-rename.h
+++ /dev/null
@@ -1,128 +0,0 @@
-#ifdef MOZ_TREE_PIXMAN
-#define pixman_region_set_static_pointers _moz_pixman_region_set_static_pointers
-#define pixman_region_init _moz_pixman_region_init
-#define pixman_region_init_rect _moz_pixman_region_init_rect
-#define pixman_region_init_rects _moz_pixman_region_init_rects
-#define pixman_region_init_with_extents _moz_pixman_region_init_with_extents
-#define pixman_region_fini _moz_pixman_region_fini
-#define pixman_region_translate _moz_pixman_region_translate
-#define pixman_region_copy _moz_pixman_region_copy
-#define pixman_region_intersect _moz_pixman_region_intersect
-#define pixman_region_union _moz_pixman_region_union
-#define pixman_region_union_rect _moz_pixman_region_union_rect
-#define pixman_region_subtract _moz_pixman_region_subtract
-#define pixman_region_inverse _moz_pixman_region_inverse
-#define pixman_region_contains_point _moz_pixman_region_contains_point
-#define pixman_region_contains_rectangle _moz_pixman_region_contains_rectangle
-#define pixman_region_not_empty _moz_pixman_region_not_empty
-#define pixman_region_extents _moz_pixman_region_extents
-#define pixman_region_n_rects _moz_pixman_region_n_rects
-#define pixman_region_rectangles _moz_pixman_region_rectangles
-#define pixman_region_equal _moz_pixman_region_equal
-#define pixman_region_selfcheck _moz_pixman_region_selfcheck
-#define pixman_region_reset _moz_pixman_region_reset
-#define pixman_region32_init _moz_pixman_region32_init
-#define pixman_region32_init_rect _moz_pixman_region32_init_rect
-#define pixman_region32_init_rects _moz_pixman_region32_init_rects
-#define pixman_region32_init_with_extents _moz_pixman_region32_init_with_extents
-#define pixman_region32_init_from_image _moz_pixman_region32_init_from_image
-#define pixman_region32_fini _moz_pixman_region32_fini
-#define pixman_region32_translate _moz_pixman_region32_translate
-#define pixman_region32_copy _moz_pixman_region32_copy
-#define pixman_region32_intersect _moz_pixman_region32_intersect
-#define pixman_region32_intersect_rect _moz_pixman_region32_intersect_rect
-#define pixman_region32_union _moz_pixman_region32_union
-#define pixman_region32_union_rect _moz_pixman_region32_union_rect
-#define pixman_region32_subtract _moz_pixman_region32_subtract
-#define pixman_region32_inverse _moz_pixman_region32_inverse
-#define pixman_region32_contains_point _moz_pixman_region32_contains_point
-#define pixman_region32_contains_rectangle _moz_pixman_region32_contains_rectangle
-#define pixman_region32_not_empty _moz_pixman_region32_not_empty
-#define pixman_region32_extents _moz_pixman_region32_extents
-#define pixman_region32_n_rects _moz_pixman_region32_n_rects
-#define pixman_region32_rectangles _moz_pixman_region32_rectangles
-#define pixman_region32_equal _moz_pixman_region32_equal
-#define pixman_region32_selfcheck _moz_pixman_region32_selfcheck
-#define pixman_region32_reset _moz_pixman_region32_reset
-#define pixman_region32_clear _moz_pixman_region32_clear
-#define pixman_blt _moz_pixman_blt
-#define pixman_fill _moz_pixman_fill
-#define pixman_transform_point_3d _moz_pixman_transform_point_3d
-#define pixman_version _moz_pixman_version
-#define pixman_version_string _moz_pixman_version_string
-#define pixman_format_supported_destination _moz_pixman_format_supported_destination
-#define pixman_format_supported_source _moz_pixman_format_supported_source
-#define pixman_image_create_solid_fill _moz_pixman_image_create_solid_fill
-#define pixman_image_create_linear_gradient _moz_pixman_image_create_linear_gradient
-#define pixman_image_create_radial_gradient _moz_pixman_image_create_radial_gradient
-#define pixman_image_create_conical_gradient _moz_pixman_image_create_conical_gradient
-#define pixman_image_create_bits _moz_pixman_image_create_bits
-#define pixman_image_ref _moz_pixman_image_ref
-#define pixman_image_unref _moz_pixman_image_unref
-#define pixman_image_set_clip_region _moz_pixman_image_set_clip_region
-#define pixman_image_set_clip_region32 _moz_pixman_image_set_clip_region32
-#define pixman_image_set_has_client_clip _moz_pixman_image_set_has_client_clip
-#define pixman_image_set_transform _moz_pixman_image_set_transform
-#define pixman_image_set_repeat _moz_pixman_image_set_repeat
-#define pixman_image_set_filter _moz_pixman_image_set_filter
-#define pixman_image_set_source_clipping _moz_pixman_image_set_source_clipping
-#define pixman_image_set_alpha_map _moz_pixman_image_set_alpha_map
-#define pixman_image_set_component_alpha _moz_pixman_image_set_component_alpha
-#define pixman_image_set_accessors	 _moz_pixman_image_set_accessors	
-#define pixman_image_set_indexed	 _moz_pixman_image_set_indexed	
-#define pixman_image_get_data _moz_pixman_image_get_data
-#define pixman_image_get_width _moz_pixman_image_get_width
-#define pixman_image_get_height _moz_pixman_image_get_height
-#define pixman_image_get_stride _moz_pixman_image_get_stride
-#define pixman_image_get_depth _moz_pixman_image_get_depth
-#define pixman_image_fill_rectangles	 _moz_pixman_image_fill_rectangles	
-#define pixman_compute_composite_region _moz_pixman_compute_composite_region
-#define pixman_image_composite _moz_pixman_image_composite
-#define pixman_sample_ceil_y _moz_pixman_sample_ceil_y
-#define pixman_sample_floor_y _moz_pixman_sample_floor_y
-#define pixman_edge_step _moz_pixman_edge_step
-#define pixman_edge_init _moz_pixman_edge_init
-#define pixman_line_fixed_edge_init _moz_pixman_line_fixed_edge_init
-#define pixman_rasterize_edges _moz_pixman_rasterize_edges
-#define pixman_add_traps _moz_pixman_add_traps
-#define pixman_add_trapezoids _moz_pixman_add_trapezoids
-#define pixman_rasterize_trapezoid _moz_pixman_rasterize_trapezoid
-#define pixman_disable_out_of_bounds_workaround _moz_pixman_disable_out_of_bounds_workaround
-#define pixman_f_transform_bounds _moz_pixman_f_transform_bounds
-#define pixman_f_transform_from_pixman_transform _moz_pixman_f_transform_from_pixman_transform
-#define pixman_f_transform_init_identity _moz_pixman_f_transform_init_identity
-#define pixman_f_transform_init_rotate _moz_pixman_f_transform_init_rotate
-#define pixman_f_transform_init_scale _moz_pixman_f_transform_init_scale
-#define pixman_f_transform_init_translate _moz_pixman_f_transform_init_translate
-#define pixman_f_transform_invert _moz_pixman_f_transform_invert
-#define pixman_f_transform_multiply _moz_pixman_f_transform_multiply
-#define pixman_f_transform_point _moz_pixman_f_transform_point
-#define pixman_f_transform_point_3d _moz_pixman_f_transform_point_3d
-#define pixman_f_transform_rotate _moz_pixman_f_transform_rotate
-#define pixman_f_transform_scale _moz_pixman_f_transform_scale
-#define pixman_f_transform_translate _moz_pixman_f_transform_translate
-#define pixman_image_composite32 _moz_pixman_image_composite32
-#define pixman_image_fill_boxes _moz_pixman_image_fill_boxes
-#define pixman_image_get_component_alpha _moz_pixman_image_get_component_alpha
-#define pixman_image_get_destroy_data _moz_pixman_image_get_destroy_data
-#define pixman_image_get_format _moz_pixman_image_get_format
-#define pixman_image_set_destroy_function _moz_pixman_image_set_destroy_function
-#define pixman_region_init_from_image _moz_pixman_region_init_from_image
-#define pixman_region_intersect_rect _moz_pixman_region_intersect_rect
-#define pixman_transform_bounds _moz_pixman_transform_bounds
-#define pixman_transform_from_pixman_f_transform _moz_pixman_transform_from_pixman_f_transform
-#define pixman_transform_init_identity _moz_pixman_transform_init_identity
-#define pixman_transform_init_rotate _moz_pixman_transform_init_rotate
-#define pixman_transform_init_scale _moz_pixman_transform_init_scale
-#define pixman_transform_init_translate _moz_pixman_transform_init_translate
-#define pixman_transform_invert _moz_pixman_transform_invert
-#define pixman_transform_is_identity _moz_pixman_transform_is_identity
-#define pixman_transform_is_int_translate _moz_pixman_transform_is_int_translate
-#define pixman_transform_is_inverse _moz_pixman_transform_is_inverse
-#define pixman_transform_is_scale _moz_pixman_transform_is_scale
-#define pixman_transform_multiply _moz_pixman_transform_multiply
-#define pixman_transform_point _moz_pixman_transform_point
-#define pixman_transform_rotate _moz_pixman_transform_rotate
-#define pixman_transform_scale _moz_pixman_transform_scale
-#define pixman_transform_translate _moz_pixman_transform_translate
-#endif
--- a/gfx/cairo/libpixman/src/pixman-compiler.h
+++ b/gfx/cairo/libpixman/src/pixman-compiler.h
@@ -80,29 +80,17 @@
 #   endif
 #   ifndef noinline
 #      define noinline
 #   endif
 #endif
 
 /* In libxul builds we don't ever want to export pixman symbols */
 #if 1
-#include "prcpucfg.h"
-
-#ifdef HAVE_VISIBILITY_HIDDEN_ATTRIBUTE
-#define CVISIBILITY_HIDDEN __attribute__((visibility("hidden")))
-#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
-#define CVISIBILITY_HIDDEN __hidden
-#else
-#define CVISIBILITY_HIDDEN
-#endif
-
-/* In libxul builds we don't ever want to export cairo symbols */
-#define PIXMAN_EXPORT extern CVISIBILITY_HIDDEN
-
+#   define PIXMAN_EXPORT cairo_public
 #else
 
 /* GCC visibility */
 #if defined(__GNUC__) && __GNUC__ >= 4 && !defined(_WIN32)
 #   define PIXMAN_EXPORT __attribute__ ((visibility("default")))
 /* Sun Studio 8 visibility */
 #elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
 #   define PIXMAN_EXPORT __global
--- a/gfx/cairo/libpixman/src/pixman.h
+++ b/gfx/cairo/libpixman/src/pixman.h
@@ -64,20 +64,17 @@ SOFTWARE.
  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
 #ifndef PIXMAN_H__
 #define PIXMAN_H__
 
-#ifdef MOZILLA_VERSION
-#include "cairo/pixman-rename.h"
-#endif
-
+#include "cairo-platform.h"
 
 #include <pixman-version.h>
 
 #ifdef  __cplusplus
 #define PIXMAN_BEGIN_DECLS extern "C" {
 #define PIXMAN_END_DECLS }
 #else
 #define PIXMAN_BEGIN_DECLS
--- a/gfx/src/nsRegion.cpp
+++ b/gfx/src/nsRegion.cpp
@@ -1,236 +1,1415 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "nsRegion.h"
+#include <algorithm>                    // for max, min
+#include "mozilla/Assertions.h"         // for MOZ_ASSERT_HELPER2, etc
+#include "mozilla/ThreadLocal.h"        // for ThreadLocal
+#include "mozilla/mozalloc.h"           // for operator delete, etc
+#include "nsDebug.h"                    // for NS_ASSERTION, NS_ERROR
+#include "nsISupports.h"                // for NS_ASSERT_OWNINGTHREAD, etc
+#include "nsPrintfCString.h"            // for nsPrintfCString
+#include "nsTArray.h"                   // for nsTArray, nsTArray_Impl, etc
 
-#include "nsRegion.h"
-#include "nsPrintfCString.h"
-#include "nsTArray.h"
+/*
+ * The SENTINEL values below guaranties that a < or >
+ * comparison with it will be false for all values of the
+ * underlying nscoord type.  E.g. this is always false:
+ *   aCoord > NS_COORD_GREATER_SENTINEL
+ * Setting the mRectListHead dummy rectangle to these values
+ * allows us to loop without checking for the list end.
+ */
+#ifdef NS_COORD_IS_FLOAT
+#define NS_COORD_LESS_SENTINEL nscoord_MIN
+#define NS_COORD_GREATER_SENTINEL nscoord_MAX
+#else
+#define NS_COORD_LESS_SENTINEL INT32_MIN
+#define NS_COORD_GREATER_SENTINEL INT32_MAX
+#endif
+
+// Fast inline analogues of nsRect methods for nsRegion::nsRectFast.
+// Check for emptiness is not required - it is guaranteed by caller.
+
+inline bool nsRegion::nsRectFast::Contains (const nsRect& aRect) const
+{
+  return (bool) ((aRect.x >= x) && (aRect.y >= y) &&
+                   (aRect.XMost () <= XMost ()) && (aRect.YMost () <= YMost ()));
+}
+
+inline bool nsRegion::nsRectFast::Intersects (const nsRect& aRect) const
+{
+  return (bool) ((x < aRect.XMost ()) && (y < aRect.YMost ()) &&
+                   (aRect.x < XMost ()) && (aRect.y < YMost ()));
+}
+
+inline bool nsRegion::nsRectFast::IntersectRect (const nsRect& aRect1, const nsRect& aRect2)
+{
+  const nscoord xmost = std::min (aRect1.XMost (), aRect2.XMost ());
+  x = std::max (aRect1.x, aRect2.x);
+  width = xmost - x;
+  if (width <= 0) return false;
+
+  const nscoord ymost = std::min (aRect1.YMost (), aRect2.YMost ());
+  y = std::max (aRect1.y, aRect2.y);
+  height = ymost - y;
+  if (height <= 0) return false;
+
+  return true;
+}
+
+inline void nsRegion::nsRectFast::UnionRect (const nsRect& aRect1, const nsRect& aRect2)
+{
+  const nscoord xmost = std::max (aRect1.XMost (), aRect2.XMost ());
+  const nscoord ymost = std::max (aRect1.YMost (), aRect2.YMost ());
+  x = std::min(aRect1.x, aRect2.x);
+  y = std::min(aRect1.y, aRect2.y);
+  width  = xmost - x;
+  height = ymost - y;
+}
+
+
+
+// Custom memory allocator for nsRegion::RgnRect structures.
+// Entries are allocated from global memory pool.
+// Memory pool can grow in size, but it can't shrink.
+
+#define INIT_MEM_CHUNK_ENTRIES 100
+#define INCR_MEM_CHUNK_ENTRIES 100
+
+class RgnRectMemoryAllocator
+{
+  nsRegion::RgnRect*  mFreeListHead;
+  uint32_t  mFreeEntries;
+  void*     mChunkListHead;
+#if defined (DEBUG)
+  NS_DECL_OWNINGTHREAD
+
+  void InitLock ()    { NS_ASSERT_OWNINGTHREAD (RgnRectMemoryAllocator); }
+  void DestroyLock () { NS_ASSERT_OWNINGTHREAD (RgnRectMemoryAllocator); }
+  void Lock ()        { NS_ASSERT_OWNINGTHREAD (RgnRectMemoryAllocator); }
+  void Unlock ()      { NS_ASSERT_OWNINGTHREAD (RgnRectMemoryAllocator); }
+#else
+  void InitLock ()    { }
+  void DestroyLock () { }
+  void Lock ()        { }
+  void Unlock ()      { }
+#endif
+
+  void* AllocChunk (uint32_t aEntries, void* aNextChunk, nsRegion::RgnRect* aTailDest)
+  {
+    uint8_t* pBuf = new uint8_t [aEntries * sizeof (nsRegion::RgnRect) + sizeof (void*)];
+    *reinterpret_cast<void**>(pBuf) = aNextChunk;
+    nsRegion::RgnRect* pRect = reinterpret_cast<nsRegion::RgnRect*>(pBuf + sizeof (void*));
+
+    for (uint32_t cnt = 0 ; cnt < aEntries - 1 ; cnt++)
+      pRect [cnt].next = &pRect [cnt + 1];
+
+    pRect [aEntries - 1].next = aTailDest;
+
+    return pBuf;
+  }
+
+  void FreeChunk (void* aChunk) {  delete [] (uint8_t *) aChunk;  }
+  void* NextChunk (void* aThisChunk) const { return *static_cast<void**>(aThisChunk); }
+
+  nsRegion::RgnRect* ChunkHead (void* aThisChunk) const
+  {   return reinterpret_cast<nsRegion::RgnRect*>(static_cast<uint8_t*>(aThisChunk) + sizeof (void*));  }
+
+public:
+  RgnRectMemoryAllocator (uint32_t aNumOfEntries);
+ ~RgnRectMemoryAllocator ();
+
+  nsRegion::RgnRect* Alloc ();
+  void Free (nsRegion::RgnRect* aRect);
+};
+
+
+RgnRectMemoryAllocator::RgnRectMemoryAllocator (uint32_t aNumOfEntries)
+{
+  InitLock ();
+  mChunkListHead = AllocChunk (aNumOfEntries, nullptr, nullptr);
+  mFreeEntries   = aNumOfEntries;
+  mFreeListHead  = ChunkHead (mChunkListHead);
+}
+
+RgnRectMemoryAllocator::~RgnRectMemoryAllocator ()
+{
+  while (mChunkListHead)
+  {
+    void* tmp = mChunkListHead;
+    mChunkListHead = NextChunk (mChunkListHead);
+    FreeChunk (tmp);
+  }
+
+#if 0
+  /*
+   * As a static object this class outlives any library which would implement
+   * locking. So we intentionally leak the 'lock'.
+   *
+   * Currently RgnRectMemoryAllocator is only used from the primary thread,
+   * so we aren't using a lock which means that there is no lock to leak.
+   * If we ever switch to multiple GUI threads (e.g. one per window),
+   * we'd probably use one allocator per window-thread to avoid the
+   * locking overhead and just require consumers not to pass regions
+   * across threads/windows, which would be a reasonable restriction
+   * because they wouldn't be useful outside their window.
+   */
+  DestroyLock ();
+#endif
+}
+
+nsRegion::RgnRect* RgnRectMemoryAllocator::Alloc ()
+{
+  Lock ();
+
+  if (mFreeEntries == 0)
+  {
+    mChunkListHead = AllocChunk (INCR_MEM_CHUNK_ENTRIES, mChunkListHead, mFreeListHead);
+    mFreeEntries   = INCR_MEM_CHUNK_ENTRIES;
+    mFreeListHead  = ChunkHead (mChunkListHead);
+  }
+
+  nsRegion::RgnRect* tmp = mFreeListHead;
+  mFreeListHead = mFreeListHead->next;
+  mFreeEntries--;
+  Unlock ();
+
+  return tmp;
+}
+
+void RgnRectMemoryAllocator::Free (nsRegion::RgnRect* aRect)
+{
+  Lock ();
+  mFreeEntries++;
+  aRect->next = mFreeListHead;
+  mFreeListHead = aRect;
+  Unlock ();
+}
+
+
+// Global pool for nsRegion::RgnRect allocation
+mozilla::ThreadLocal<RgnRectMemoryAllocator*> gRectPoolTlsIndex;
+
+void RgnRectMemoryAllocatorDTOR(void *priv)
+{
+  RgnRectMemoryAllocator* allocator = gRectPoolTlsIndex.get();
+  delete allocator;
+}
+
+nsresult nsRegion::InitStatic()
+{
+  if (gRectPoolTlsIndex.initialized()) {
+    // It's ok to call InitStatic if we called ShutdownStatic first
+    MOZ_ASSERT(gRectPoolTlsIndex.get() == nullptr);
+    return NS_OK;
+  }
+
+  return gRectPoolTlsIndex.init() ? NS_OK : NS_ERROR_FAILURE;
+}
+
+void nsRegion::ShutdownStatic()
+{
+  RgnRectMemoryAllocator* allocator = gRectPoolTlsIndex.get();
+  if (!allocator)
+    return;
+
+  delete allocator;
+
+  gRectPoolTlsIndex.set(nullptr);
+}
+
+void* nsRegion::RgnRect::operator new (size_t) CPP_THROW_NEW
+{
+  RgnRectMemoryAllocator* allocator = gRectPoolTlsIndex.get();
+  if (!allocator) {
+    allocator = new RgnRectMemoryAllocator(INIT_MEM_CHUNK_ENTRIES);
+    gRectPoolTlsIndex.set(allocator);
+  }
+  return allocator->Alloc ();
+}
+
+void nsRegion::RgnRect::operator delete (void* aRect, size_t)
+{
+  RgnRectMemoryAllocator* allocator = gRectPoolTlsIndex.get();
+  if (!allocator) {
+    NS_ERROR("Invalid nsRegion::RgnRect delete");
+    return;
+  }
+  allocator->Free (static_cast<RgnRect*>(aRect));
+}
+
+
+
+void nsRegion::Init()
+{
+  mRectListHead.prev = mRectListHead.next = &mRectListHead;
+  mCurRect = &mRectListHead;
+  mRectCount = 0;
+  mBoundRect.SetRect (0, 0, 0, 0);
+}
+
+inline void nsRegion::InsertBefore (RgnRect* aNewRect, RgnRect* aRelativeRect)
+{
+  aNewRect->prev = aRelativeRect->prev;
+  aNewRect->next = aRelativeRect;
+  aRelativeRect->prev->next = aNewRect;
+  aRelativeRect->prev = aNewRect;
+  mCurRect = aNewRect;
+  mRectCount++;
+}
+
+inline void nsRegion::InsertAfter (RgnRect* aNewRect, RgnRect* aRelativeRect)
+{
+  aNewRect->prev = aRelativeRect;
+  aNewRect->next = aRelativeRect->next;
+  aRelativeRect->next->prev = aNewRect;
+  aRelativeRect->next = aNewRect;
+  mCurRect = aNewRect;
+  mRectCount++;
+}
+
+
+// Adjust the number of rectangles in region.
+// Content of rectangles should be changed by caller.
+
+void nsRegion::SetToElements (uint32_t aCount)
+{
+  if (mRectCount < aCount)        // Add missing rectangles
+  {
+    uint32_t InsertCount = aCount - mRectCount;
+    mRectCount = aCount;
+    RgnRect* pPrev = &mRectListHead;
+    RgnRect* pNext = mRectListHead.next;
+
+    while (InsertCount--)
+    {
+      mCurRect = new RgnRect;
+      mCurRect->prev = pPrev;
+      pPrev->next = mCurRect;
+      pPrev = mCurRect;
+    }
+
+    pPrev->next = pNext;
+    pNext->prev = pPrev;
+  } else
+  if (mRectCount > aCount)        // Remove unnecessary rectangles
+  {
+    uint32_t RemoveCount = mRectCount - aCount;
+    mRectCount = aCount;
+    mCurRect = mRectListHead.next;
+
+    while (RemoveCount--)
+    {
+      RgnRect* tmp = mCurRect;
+      mCurRect = mCurRect->next;
+      delete tmp;
+    }
+
+    mRectListHead.next = mCurRect;
+    mCurRect->prev = &mRectListHead;
+  }
+}
+
+
+// Save the entire chain of linked elements in 'prev' field of the RgnRect structure.
+// After that forward-only iterations using 'next' field could still be used.
+// Some elements from forward-only chain could be temporarily removed to optimize inner loops.
+// The original double linked state could be restored by call to RestoreLinkChain ().
+// Both functions despite size can be inline because they are called only from one function.
+
+inline void nsRegion::SaveLinkChain ()
+{
+  RgnRect* pRect = &mRectListHead;
+
+  do
+  {
+    pRect->prev = pRect->next;
+    pRect = pRect->next;
+  } while (pRect != &mRectListHead);
+}
+
+
+inline void nsRegion::RestoreLinkChain ()
+{
+  RgnRect* pPrev = &mRectListHead;
+  RgnRect* pRect = mRectListHead.next = mRectListHead.prev;
+
+  while (pRect != &mRectListHead)
+  {
+    pRect->next = pRect->prev;
+    pRect->prev = pPrev;
+    pPrev = pRect;
+    pRect = pRect->next;
+  }
+
+  mRectListHead.prev = pPrev;
+}
+
+
+// Insert node in right place of sorted list
+// If necessary then bounding rectangle could be updated and rectangle combined
+// with neighbour rectangles. This is usually done in Optimize ()
+
+void nsRegion::InsertInPlace (RgnRect* aRect, bool aOptimizeOnFly)
+{
+  if (mRectCount == 0)
+    InsertAfter (aRect, &mRectListHead);
+  else
+  {
+    if (aRect->y > mCurRect->y)
+    {
+      mRectListHead.y = NS_COORD_GREATER_SENTINEL;
+      while (aRect->y > mCurRect->next->y)
+        mCurRect = mCurRect->next;
+
+      mRectListHead.x = NS_COORD_GREATER_SENTINEL;
+      while (aRect->y == mCurRect->next->y && aRect->x > mCurRect->next->x)
+        mCurRect = mCurRect->next;
+
+      InsertAfter (aRect, mCurRect);
+    } else
+    if (aRect->y < mCurRect->y)
+    {
+      mRectListHead.y = NS_COORD_LESS_SENTINEL;
+      while (aRect->y < mCurRect->prev->y)
+        mCurRect = mCurRect->prev;
+
+      mRectListHead.x = NS_COORD_LESS_SENTINEL;
+      while (aRect->y == mCurRect->prev->y && aRect->x < mCurRect->prev->x)
+        mCurRect = mCurRect->prev;
+
+      InsertBefore (aRect, mCurRect);
+    } else
+    {
+      if (aRect->x > mCurRect->x)
+      {
+        mRectListHead.x = NS_COORD_GREATER_SENTINEL;
+        while (aRect->y == mCurRect->next->y && aRect->x > mCurRect->next->x)
+          mCurRect = mCurRect->next;
+
+        InsertAfter (aRect, mCurRect);
+      } else
+      {
+        mRectListHead.x = NS_COORD_LESS_SENTINEL;
+        while (aRect->y == mCurRect->prev->y && aRect->x < mCurRect->prev->x)
+          mCurRect = mCurRect->prev;
+
+        InsertBefore (aRect, mCurRect);
+      }
+    }
+  }
+
+
+  if (aOptimizeOnFly)
+  {
+    if (mRectCount == 1)
+      mBoundRect = *mCurRect;
+    else
+    {
+      mBoundRect.UnionRect (mBoundRect, *mCurRect);
+
+      // Check if we can go left or up before starting to combine rectangles
+      if ((mCurRect->y == mCurRect->prev->y && mCurRect->height == mCurRect->prev->height &&
+           mCurRect->x == mCurRect->prev->XMost ()) ||
+          (mCurRect->x == mCurRect->prev->x && mCurRect->width == mCurRect->prev->width &&
+           mCurRect->y == mCurRect->prev->YMost ()) )
+        mCurRect = mCurRect->prev;
+
+      // Try to combine with rectangle on right side
+      while (mCurRect->y == mCurRect->next->y && mCurRect->height == mCurRect->next->height &&
+             mCurRect->XMost () == mCurRect->next->x)
+      {
+        mCurRect->width += mCurRect->next->width;
+        delete Remove (mCurRect->next);
+      }
+
+      // Try to combine with rectangle under this one
+      while (mCurRect->x == mCurRect->next->x && mCurRect->width == mCurRect->next->width &&
+             mCurRect->YMost () == mCurRect->next->y)
+      {
+        mCurRect->height += mCurRect->next->height;
+        delete Remove (mCurRect->next);
+      }
+    }
+  }
+}
+
+
+nsRegion::RgnRect* nsRegion::Remove (RgnRect* aRect)
+{
+  aRect->prev->next = aRect->next;
+  aRect->next->prev = aRect->prev;
+  mRectCount--;
+
+  if (mCurRect == aRect)
+    mCurRect = (aRect->next != &mRectListHead) ? aRect->next : aRect->prev;
+
+  return aRect;
+}
+
+
+// Try to reduce the number of rectangles in complex region by combining with
+// surrounding ones on right and bottom sides of each rectangle in list.
+// Update bounding rectangle
+
+void nsRegion::Optimize ()
+{
+  if (mRectCount == 0)
+    mBoundRect.SetRect (0, 0, 0, 0);
+  else
+  {
+    RgnRect* pRect = mRectListHead.next;
+    int32_t xmost = mRectListHead.prev->XMost ();
+    int32_t ymost = mRectListHead.prev->YMost ();
+    mBoundRect.x = mRectListHead.next->x;
+    mBoundRect.y = mRectListHead.next->y;
+
+    while (pRect != &mRectListHead)
+    {
+      // Try to combine with rectangle on right side
+      while (pRect->y == pRect->next->y && pRect->height == pRect->next->height &&
+             pRect->XMost () == pRect->next->x)
+      {
+        pRect->width += pRect->next->width;
+        delete Remove (pRect->next);
+      }
+
+      // Try to combine with rectangle under this one
+      while (pRect->x == pRect->next->x && pRect->width == pRect->next->width &&
+             pRect->YMost () == pRect->next->y)
+      {
+        pRect->height += pRect->next->height;
+        delete Remove (pRect->next);
+      }
+
+      // Determine bound rectangle. Use fact that rectangles are sorted.
+      if (pRect->x < mBoundRect.x) mBoundRect.x = pRect->x;
+      if (pRect->XMost () > xmost) xmost = pRect->XMost ();
+      if (pRect->YMost () > ymost) ymost = pRect->YMost ();
+
+      pRect = pRect->next;
+    }
+
+    mBoundRect.width  = xmost - mBoundRect.x;
+    mBoundRect.height = ymost - mBoundRect.y;
+  }
+}
 
 
-bool nsRegion::Contains(const nsRegion& aRgn) const
+// Move rectangles starting from 'aStartRect' till end of the list to the destionation region.
+// Important for temporary objects - instead of copying rectangles with Merge () and then
+// emptying region in destructor they could be moved to destination region in one step.
+
+void nsRegion::MoveInto (nsRegion& aDestRegion, const RgnRect* aStartRect)
+{
+  RgnRect* pRect = const_cast<RgnRect*>(aStartRect);
+  RgnRect* pPrev = pRect->prev;
+
+  while (pRect != &mRectListHead)
+  {
+    RgnRect* next = pRect->next;
+    aDestRegion.InsertInPlace (pRect);
+
+    mRectCount--;
+    pRect = next;
+  }
+
+  pPrev->next = &mRectListHead;
+  mRectListHead.prev = pPrev;
+  mCurRect = mRectListHead.next;
+}
+
+
+// Merge two non-overlapping regions into one.
+// Automatically optimize region by calling Optimize ()
+
+void nsRegion::Merge (const nsRegion& aRgn1, const nsRegion& aRgn2)
+{
+  if (aRgn1.mRectCount == 0)            // Region empty. Result is equal to other region
+    Copy (aRgn2);
+  else
+  if (aRgn2.mRectCount == 0)            // Region empty. Result is equal to other region
+    Copy (aRgn1);
+  if (aRgn1.mRectCount == 1)            // Region is single rectangle. Optimize on fly
+  {
+    RgnRect* TmpRect = new RgnRect (*aRgn1.mRectListHead.next);
+    Copy (aRgn2);
+    InsertInPlace (TmpRect, true);
+  } else
+  if (aRgn2.mRectCount == 1)            // Region is single rectangle. Optimize on fly
+  {
+    RgnRect* TmpRect = new RgnRect (*aRgn2.mRectListHead.next);
+    Copy (aRgn1);
+    InsertInPlace (TmpRect, true);
+  } else
+  {
+    const nsRegion* pCopyRegion, *pInsertRegion;
+
+    // Determine which region contains more rectangles. Copy the larger one
+    if (aRgn1.mRectCount >= aRgn2.mRectCount)
+    {
+      pCopyRegion = &aRgn1;
+      pInsertRegion = &aRgn2;
+    } else
+    {
+      pCopyRegion = &aRgn2;
+      pInsertRegion = &aRgn1;
+    }
+
+    if (pInsertRegion == this)          // Do merge in-place
+      pInsertRegion = pCopyRegion;
+    else
+      Copy (*pCopyRegion);
+
+    const RgnRect* pSrcRect = pInsertRegion->mRectListHead.next;
+
+    while (pSrcRect != &pInsertRegion->mRectListHead)
+    {
+      InsertInPlace (new RgnRect (*pSrcRect));
+
+      pSrcRect = pSrcRect->next;
+    }
+
+    Optimize ();
+  }
+}
+
+
+nsRegion& nsRegion::Copy (const nsRegion& aRegion)
+{
+  if (&aRegion == this)
+    return *this;
+
+  if (aRegion.mRectCount == 0)
+    SetEmpty ();
+  else
+  {
+    SetToElements (aRegion.mRectCount);
+
+    const RgnRect* pSrc = aRegion.mRectListHead.next;
+    RgnRect* pDest = mRectListHead.next;
+
+    while (pSrc != &aRegion.mRectListHead)
+    {
+      *pDest = *pSrc;
+
+      pSrc  = pSrc->next;
+      pDest = pDest->next;
+    }
+
+    mCurRect = mRectListHead.next;
+    mBoundRect = aRegion.mBoundRect;
+  }
+
+  return *this;
+}
+
+
+nsRegion& nsRegion::Copy (const nsRect& aRect)
+{
+  if (aRect.IsEmpty ())
+    SetEmpty ();
+  else
+  {
+    SetToElements (1);
+    *mRectListHead.next = static_cast<const RgnRect&>(aRect);
+    mBoundRect = static_cast<const nsRectFast&>(aRect);
+  }
+
+  return *this;
+}
+
+
+nsRegion& nsRegion::And (const nsRegion& aRgn1, const nsRegion& aRgn2)
+{
+  if (&aRgn1 == &aRgn2)                                       // And with self
+    Copy (aRgn1);
+  else
+  if (aRgn1.mRectCount == 0 || aRgn2.mRectCount == 0)         // If either region is empty then result is empty
+    SetEmpty ();
+  else
+  {
+    nsRectFast TmpRect;
+
+    if (aRgn1.mRectCount == 1 && aRgn2.mRectCount == 1)       // Intersect rectangle with rectangle
+    {
+      TmpRect.IntersectRect (*aRgn1.mRectListHead.next, *aRgn2.mRectListHead.next);
+      Copy (TmpRect);
+    } else
+    {
+      if (!aRgn1.mBoundRect.Intersects (aRgn2.mBoundRect))    // Regions do not intersect
+        SetEmpty ();
+      else
+      {
+        // Region is simple rectangle and it fully overlays other region
+        if (aRgn1.mRectCount == 1 && aRgn1.mBoundRect.Contains (aRgn2.mBoundRect))
+          Copy (aRgn2);
+        else
+        // Region is simple rectangle and it fully overlays other region
+        if (aRgn2.mRectCount == 1 && aRgn2.mBoundRect.Contains (aRgn1.mBoundRect))
+          Copy (aRgn1);
+        else
+        {
+          nsRegion TmpRegion;
+          nsRegion* pSrcRgn1 = const_cast<nsRegion*>(&aRgn1);
+          nsRegion* pSrcRgn2 = const_cast<nsRegion*>(&aRgn2);
+
+          if (&aRgn1 == this)     // Copy region if it is both source and result
+          {
+            TmpRegion.Copy (aRgn1);
+            pSrcRgn1 = &TmpRegion;
+          }
+
+          if (&aRgn2 == this)     // Copy region if it is both source and result
+          {
+            TmpRegion.Copy (aRgn2);
+            pSrcRgn2 = &TmpRegion;
+          }
+
+          // For outer loop prefer region for which at least one rectangle is below other's bound rectangle
+          if (pSrcRgn2->mRectListHead.prev->y >= pSrcRgn1->mBoundRect.YMost ())
+          {
+            nsRegion* Tmp = pSrcRgn1;
+            pSrcRgn1 = pSrcRgn2;
+            pSrcRgn2 = Tmp;
+          }
+
+
+          SetToElements (0);
+          pSrcRgn2->SaveLinkChain ();
+
+          pSrcRgn1->mRectListHead.y = NS_COORD_GREATER_SENTINEL;
+          pSrcRgn2->mRectListHead.y = NS_COORD_GREATER_SENTINEL;
+
+          for (RgnRect* pSrcRect1 = pSrcRgn1->mRectListHead.next ;
+               pSrcRect1->y < pSrcRgn2->mBoundRect.YMost () ; pSrcRect1 = pSrcRect1->next)
+          {
+            if (pSrcRect1->Intersects (pSrcRgn2->mBoundRect))   // Rectangle intersects region. Process each rectangle
+            {
+              RgnRect* pPrev2 = &pSrcRgn2->mRectListHead;
+
+              for (RgnRect* pSrcRect2 = pSrcRgn2->mRectListHead.next ;
+                   pSrcRect2->y < pSrcRect1->YMost () ; pSrcRect2 = pSrcRect2->next)
+              {
+                if (pSrcRect2->YMost () <= pSrcRect1->y)        // Rect2's bottom is above the top of Rect1.
+                {                                               // No successive rectangles in Rgn1 can intersect it.
+                  pPrev2->next = pSrcRect2->next;               // Remove Rect2 from Rgn2's checklist
+                  continue;
+                }
+
+                if (pSrcRect1->Contains (*pSrcRect2))           // Rect1 fully overlays Rect2.
+                {                                               // No any other rectangle in Rgn1 can intersect it.
+                  pPrev2->next = pSrcRect2->next;               // Remove Rect2 from Rgn2's checklist
+                  InsertInPlace (new RgnRect (*pSrcRect2));
+                  continue;
+                }
+
+
+                if (TmpRect.IntersectRect (*pSrcRect1, *pSrcRect2))
+                  InsertInPlace (new RgnRect (TmpRect));
+
+                pPrev2 = pSrcRect2;
+              }
+            }
+          }
+
+          pSrcRgn2->RestoreLinkChain ();
+          Optimize ();
+        }
+      }
+    }
+  }
+
+  return *this;
+}
+
+
+nsRegion& nsRegion::And (const nsRegion& aRegion, const nsRect& aRect)
+{
+  // If either region or rectangle is empty then result is empty
+  if (aRegion.mRectCount == 0 || aRect.IsEmpty ())
+    SetEmpty ();
+  else                            // Intersect region with rectangle
+  {
+    const nsRectFast& aRectFast = static_cast<const nsRectFast&>(aRect);
+    nsRectFast TmpRect;
+
+    if (aRegion.mRectCount == 1)  // Intersect rectangle with rectangle
+    {
+      TmpRect.IntersectRect (*aRegion.mRectListHead.next, aRectFast);
+      Copy (TmpRect);
+    } else                        // Intersect complex region with rectangle
+    {
+      if (!aRectFast.Intersects (aRegion.mBoundRect))   // Rectangle does not intersect region
+        SetEmpty ();
+      else
+      {
+        if (aRectFast.Contains (aRegion.mBoundRect))    // Rectangle fully overlays region
+          Copy (aRegion);
+        else
+        {
+          nsRegion TmpRegion;
+          nsRegion* pSrcRegion = const_cast<nsRegion*>(&aRegion);
+
+          if (&aRegion == this)   // Copy region if it is both source and result
+          {
+            TmpRegion.Copy (aRegion);
+            pSrcRegion = &TmpRegion;
+          }
+
+          SetToElements (0);
+          pSrcRegion->mRectListHead.y = NS_COORD_GREATER_SENTINEL;
+
+          for (const RgnRect* pSrcRect = pSrcRegion->mRectListHead.next ;
+               pSrcRect->y < aRectFast.YMost () ; pSrcRect = pSrcRect->next)
+          {
+            if (TmpRect.IntersectRect (*pSrcRect, aRectFast))
+              InsertInPlace (new RgnRect (TmpRect));
+          }
+
+          Optimize ();
+        }
+      }
+    }
+  }
+
+  return *this;
+}
+
+
+nsRegion& nsRegion::Or (const nsRegion& aRgn1, const nsRegion& aRgn2)
+{
+  if (&aRgn1 == &aRgn2)                 // Or with self
+    Copy (aRgn1);
+  else
+  if (aRgn1.mRectCount == 0)            // Region empty. Result is equal to other region
+    Copy (aRgn2);
+  else
+  if (aRgn2.mRectCount == 0)            // Region empty. Result is equal to other region
+    Copy (aRgn1);
+  else
+  {
+    if (!aRgn1.mBoundRect.Intersects (aRgn2.mBoundRect))  // Regions do not intersect
+      Merge (aRgn1, aRgn2);
+    else
+    {
+      // Region is simple rectangle and it fully overlays other region
+      if (aRgn1.mRectCount == 1 && aRgn1.mBoundRect.Contains (aRgn2.mBoundRect))
+        Copy (aRgn1);
+      else
+      // Region is simple rectangle and it fully overlays other region
+      if (aRgn2.mRectCount == 1 && aRgn2.mBoundRect.Contains (aRgn1.mBoundRect))
+        Copy (aRgn2);
+      else
+      {
+        nsRegion TmpRegion;
+        aRgn1.SubRegion (aRgn2, TmpRegion);               // Get only parts of region which not overlap the other region
+        Copy (aRgn2);
+        TmpRegion.MoveInto (*this);
+        Optimize ();
+      }
+    }
+  }
+
+  return *this;
+}
+
+
+nsRegion& nsRegion::Or (const nsRegion& aRegion, const nsRect& aRect)
+{
+  if (aRegion.mRectCount == 0)          // Region empty. Result is equal to rectangle
+    Copy (aRect);
+  else
+  if (aRect.IsEmpty ())                 // Rectangle is empty. Result is equal to region
+    Copy (aRegion);
+  else
+  {
+    const nsRectFast& aRectFast = static_cast<const nsRectFast&>(aRect);
+
+    if (!aRectFast.Intersects (aRegion.mBoundRect))     // Rectangle does not intersect region
+    {
+      Copy (aRegion);
+      InsertInPlace (new RgnRect (aRectFast), true);
+    } else
+    {
+      // Region is simple rectangle and it fully overlays rectangle
+      if (aRegion.mRectCount == 1 && aRegion.mBoundRect.Contains (aRectFast))
+        Copy (aRegion);
+      else
+      if (aRectFast.Contains (aRegion.mBoundRect))      // Rectangle fully overlays region
+        Copy (aRectFast);
+      else
+      {
+        aRegion.SubRect (aRectFast, *this);             // Exclude from region parts that overlap the rectangle
+        InsertInPlace (new RgnRect (aRectFast));
+        Optimize ();
+      }
+    }
+  }
+
+  return *this;
+}
+
+
+nsRegion& nsRegion::Xor (const nsRegion& aRgn1, const nsRegion& aRgn2)
+{
+  if (&aRgn1 == &aRgn2)                 // Xor with self
+    SetEmpty ();
+  else
+  if (aRgn1.mRectCount == 0)            // Region empty. Result is equal to other region
+    Copy (aRgn2);
+  else
+  if (aRgn2.mRectCount == 0)            // Region empty. Result is equal to other region
+    Copy (aRgn1);
+  else
+  {
+    if (!aRgn1.mBoundRect.Intersects (aRgn2.mBoundRect))      // Regions do not intersect
+      Merge (aRgn1, aRgn2);
+    else
+    {
+      // Region is simple rectangle and it fully overlays other region
+      if (aRgn1.mRectCount == 1 && aRgn1.mBoundRect.Contains (aRgn2.mBoundRect))
+      {
+        aRgn1.SubRegion (aRgn2, *this);
+        Optimize ();
+      } else
+      // Region is simple rectangle and it fully overlays other region
+      if (aRgn2.mRectCount == 1 && aRgn2.mBoundRect.Contains (aRgn1.mBoundRect))
+      {
+        aRgn2.SubRegion (aRgn1, *this);
+        Optimize ();
+      } else
+      {
+        nsRegion TmpRegion;
+        aRgn1.SubRegion (aRgn2, TmpRegion);
+        aRgn2.SubRegion (aRgn1, *this);
+        TmpRegion.MoveInto (*this);
+        Optimize ();
+      }
+    }
+  }
+
+  return *this;
+}
+
+
+nsRegion& nsRegion::Xor (const nsRegion& aRegion, const nsRect& aRect)
+{
+  if (aRegion.mRectCount == 0)          // Region empty. Result is equal to rectangle
+    Copy (aRect);
+  else
+  if (aRect.IsEmpty ())                 // Rectangle is empty. Result is equal to region
+    Copy (aRegion);
+  else
+  {
+    const nsRectFast& aRectFast = static_cast<const nsRectFast&>(aRect);
+
+    if (!aRectFast.Intersects (aRegion.mBoundRect))     // Rectangle does not intersect region
+    {
+      Copy (aRegion);
+      InsertInPlace (new RgnRect (aRectFast), true);
+    } else
+    {
+      // Region is simple rectangle and it fully overlays rectangle
+      if (aRegion.mRectCount == 1 && aRegion.mBoundRect.Contains (aRectFast))
+      {
+        aRegion.SubRect (aRectFast, *this);
+        Optimize ();
+      } else
+      if (aRectFast.Contains (aRegion.mBoundRect))      // Rectangle fully overlays region
+      {
+        nsRegion TmpRegion;
+        TmpRegion.Copy (aRectFast);
+        TmpRegion.SubRegion (aRegion, *this);
+        Optimize ();
+      } else
+      {
+        nsRegion TmpRegion;
+        TmpRegion.Copy (aRectFast);
+        TmpRegion.SubRegion (aRegion, TmpRegion);
+        aRegion.SubRect (aRectFast, *this);
+        TmpRegion.MoveInto (*this);
+        Optimize ();
+      }
+    }
+  }
+
+  return *this;
+}
+
+
+nsRegion& nsRegion::Sub (const nsRegion& aRgn1, const nsRegion& aRgn2)
+{
+  if (&aRgn1 == &aRgn2)         // Sub from self
+    SetEmpty ();
+  else
+  if (aRgn1.mRectCount == 0)    // If source is empty then result is empty, too
+    SetEmpty ();
+  else
+  if (aRgn2.mRectCount == 0)    // Nothing to subtract
+    Copy (aRgn1);
+  else
+  {
+    if (!aRgn1.mBoundRect.Intersects (aRgn2.mBoundRect))   // Regions do not intersect
+      Copy (aRgn1);
+    else
+    {
+      aRgn1.SubRegion (aRgn2, *this);
+      Optimize ();
+    }
+  }
+
+  return *this;
+}
+
+
+nsRegion& nsRegion::Sub (const nsRegion& aRegion, const nsRect& aRect)
+{
+  if (aRegion.mRectCount == 0)    // If source is empty then result is empty, too
+    SetEmpty ();
+  else
+  if (aRect.IsEmpty ())           // Nothing to subtract
+    Copy (aRegion);
+  else
+  {
+    const nsRectFast& aRectFast = static_cast<const nsRectFast&>(aRect);
+
+    if (!aRectFast.Intersects (aRegion.mBoundRect))   // Rectangle does not intersect region
+      Copy (aRegion);
+    else
+    {
+      if (aRectFast.Contains (aRegion.mBoundRect))    // Rectangle fully overlays region
+        SetEmpty ();
+      else
+      {
+        aRegion.SubRect (aRectFast, *this);
+        Optimize ();
+      }
+    }
+  }
+
+  return *this;
+}
+
+bool nsRegion::Contains (const nsRect& aRect) const
+{
+  if (aRect.IsEmpty())
+    return true;
+  if (IsEmpty())
+    return false;
+  if (!IsComplex())
+    return mBoundRect.Contains (aRect);
+
+  nsRegion tmpRgn;
+  tmpRgn.Sub(aRect, *this);
+  return tmpRgn.IsEmpty();
+}
+
+bool nsRegion::Contains (const nsRegion& aRgn) const
 {
   // XXX this could be made faster
   nsRegionRectIterator iter(aRgn);
   while (const nsRect* r = iter.Next()) {
     if (!Contains (*r)) {
       return false;
     }
   }
   return true;
 }
 
-bool nsRegion::Intersects(const nsRect& aRect) const
+bool nsRegion::Intersects (const nsRect& aRect) const
 {
-  // XXX this could be made faster
-  nsRegionRectIterator iter(*this);
-  while (const nsRect* r = iter.Next()) {
-    if (r->Intersects(aRect)) {
+  if (aRect.IsEmpty() || IsEmpty())
+    return false;
+
+  const RgnRect* r = mRectListHead.next;
+  while (r != &mRectListHead)
+  {
+    if (r->Intersects(aRect))
       return true;
-    }
+    r = r->next;
   }
   return false;
 }
 
-void nsRegion::Inflate(const nsMargin& aMargin)
+// Subtract region from current region.
+// Both regions are non-empty and they intersect each other.
+// Result could be empty region if aRgn2 is rectangle that fully overlays aRgn1.
+// Optimize () is not called on exit (bound rectangle is not updated).
+
+void nsRegion::SubRegion (const nsRegion& aRegion, nsRegion& aResult) const
 {
-  int n;
-  pixman_box32_t *boxes = pixman_region32_rectangles(&mImpl, &n);
-  for (int i=0; i<n; i++) {
-    nsRect rect = BoxToRect(boxes[i]);
-    rect.Inflate(aMargin);
-    boxes[i] = RectToBox(rect);
+  if (aRegion.mRectCount == 1)    // Subtract simple rectangle
+  {
+    if (aRegion.mBoundRect.Contains (mBoundRect))
+      aResult.SetEmpty ();
+    else
+      SubRect (*aRegion.mRectListHead.next, aResult);
+  } else
+  {
+    nsRegion TmpRegion, CompletedRegion;
+    const nsRegion* pSubRgn = &aRegion;
+
+    if (&aResult == &aRegion)     // Copy region if it is both source and result
+    {
+      TmpRegion.Copy (aRegion);
+      pSubRgn = &TmpRegion;
+    }
+
+    const RgnRect* pSubRect = pSubRgn->mRectListHead.next;
+
+    SubRect (*pSubRect, aResult, CompletedRegion);
+    pSubRect = pSubRect->next;
+
+    while (pSubRect != &pSubRgn->mRectListHead)
+    {
+      aResult.SubRect (*pSubRect, aResult, CompletedRegion);
+      pSubRect = pSubRect->next;
+    }
+
+    CompletedRegion.MoveInto (aResult);
   }
-
-  pixman_region32_t region;
-  // This will union all of the rectangles and runs in about O(n lg(n))
-  pixman_region32_init_rects(&region, boxes, n);
-
-  pixman_region32_fini(&mImpl);
-  mImpl = region;
 }
 
-void nsRegion::SimplifyOutward (uint32_t aMaxRects)
-{
-  MOZ_ASSERT(aMaxRects >= 1, "Invalid max rect count");
 
-  if (GetNumRects() <= aMaxRects)
-    return;
+// Subtract rectangle from current region.
+// Both region and rectangle are non-empty and they intersect each other.
+// Result could be empty region if aRect fully overlays aRegion.
+// Could be called repeatedly with 'this' as input and result - bound rectangle is not known.
+// Optimize () is not called on exit (bound rectangle is not updated).
+//
+// aCompleted is filled with rectangles which are already checked and could be safely
+// removed from further examination in case aRect rectangles come from ordered list.
+// aCompleted is not automatically emptied. aCompleted and aResult could be the same region.
 
-  pixman_box32_t *boxes;
-  int n;
-  boxes = pixman_region32_rectangles(&mImpl, &n);
+void nsRegion::SubRect (const nsRectFast& aRect, nsRegion& aResult, nsRegion& aCompleted) const
+{
+  nsRegion TmpRegion;
+  const nsRegion* pSrcRegion = this;
 
-  // Try combining rects in horizontal bands into a single rect
-  int dest = 0;
-  for (int src = 1; src < n; src++)
+  if (&aResult == this)           // Copy region if it is both source and result
+  {
+    TmpRegion.Copy (*this);
+    pSrcRegion = &TmpRegion;
+  }
+
+  aResult.SetToElements (0);
+
+  const_cast<nsRegion*>(pSrcRegion)->mRectListHead.y = NS_COORD_GREATER_SENTINEL;
+  const RgnRect* pSrcRect = pSrcRegion->mRectListHead.next;
+
+  for ( ; pSrcRect->y < aRect.YMost () ; pSrcRect = pSrcRect->next)
   {
-    // The goal here is to try to keep groups of rectangles that are vertically
-    // discontiguous as separate rectangles in the final region. This is
-    // simple and fast to implement and page contents tend to vary more
-    // vertically than horizontally (which is why our rectangles are stored
-    // sorted by y-coordinate, too).
-    //
-    // Note: if boxes share y1 because of the canonical representation they
-    // will share y2
-    while ((src < (n)) && boxes[dest].y1 == boxes[src].y1) {
-      // merge box[i] and box[i+1]
-      boxes[dest].x2 = boxes[src].x2;
-      src++;
+    nsRectFast TmpRect;
+
+    // If bottom of current rectangle is above the top of aRect then this rectangle
+    // could be moved to aCompleted region. Successive aRect rectangles from ordered
+    // list do not have to check this rectangle again.
+    if (pSrcRect->YMost () <= aRect.y)
+    {
+      aCompleted.InsertInPlace (new RgnRect (*pSrcRect));
+      continue;
     }
-    if (src < n) {
-      dest++;
-      boxes[dest] = boxes[src];
+
+    if (!TmpRect.IntersectRect (*pSrcRect, aRect))
+      aResult.InsertInPlace (new RgnRect (*pSrcRect));
+    else
+    {
+      // Rectangle A. Subtract from this rectangle B
+      const nscoord ax  = pSrcRect->x;
+      const nscoord axm = pSrcRect->XMost ();
+      const nscoord aw  = pSrcRect->width;
+      const nscoord ay  = pSrcRect->y;
+      const nscoord aym = pSrcRect->YMost ();
+      const nscoord ah  = pSrcRect->height;
+      // Rectangle B. Subtract this from rectangle A
+      const nscoord bx  = aRect.x;
+      const nscoord bxm = aRect.XMost ();
+      const nscoord by  = aRect.y;
+      const nscoord bym = aRect.YMost ();
+      // Rectangle I. Area where rectangles A and B intersect
+      const nscoord ix  = TmpRect.x;
+      const nscoord ixm = TmpRect.XMost ();
+      const nscoord iy  = TmpRect.y;
+      const nscoord iym = TmpRect.YMost ();
+      const nscoord ih  = TmpRect.height;
+
+      // There are 16 combinations how rectangles could intersect
+
+      if (bx <= ax && by <= ay)
+      {
+        if (bxm < axm && bym < aym)     // 1.
+        {
+          aResult.InsertInPlace (new RgnRect (ixm, ay, axm - ixm, ih));
+          aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
+        } else
+        if (bxm >= axm && bym < aym)    // 2.
+        {
+          aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
+        } else
+        if (bxm < axm && bym >= aym)    // 3.
+        {
+          aResult.InsertInPlace (new RgnRect (ixm, ay, axm - ixm, ah));
+        } else
+        if (pSrcRect->IsEqualInterior(aRect)) // 4. subset
+        {                               // Current rectangle is equal to aRect
+          pSrcRect = pSrcRect->next;    // don't add this one to the result, it's removed
+          break;                        // No any other rectangle in region can intersect it
+        }
+      } else
+      if (bx > ax && by <= ay)
+      {
+        if (bxm < axm && bym < aym)     // 5.
+        {
+          aResult.InsertInPlace (new RgnRect (ax, ay, ix - ax, ih));
+          aResult.InsertInPlace (new RgnRect (ixm, ay, axm - ixm, ih));
+          aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
+        } else
+        if (bxm >= axm && bym < aym)    // 6.
+        {
+          aResult.InsertInPlace (new RgnRect (ax, ay, ix - ax, ih));
+          aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
+        } else
+        if (bxm < axm && bym >= aym)    // 7.
+        {
+          aResult.InsertInPlace (new RgnRect (ax, ay, ix - ax, ah));
+          aResult.InsertInPlace (new RgnRect (ixm, ay, axm - ixm, ah));
+        } else
+        if (bxm >= axm && bym >= aym)   // 8.
+        {
+          aResult.InsertInPlace (new RgnRect (ax, ay, ix - ax, ah));
+        }
+      } else
+      if (bx <= ax && by > ay)
+      {
+        if (bxm < axm && bym < aym)     // 9.
+        {
+          aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
+          aResult.InsertInPlace (new RgnRect (ixm, iy, axm - ixm, ih));
+          aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
+        } else
+        if (bxm >= axm && bym < aym)    // 10.
+        {
+          aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
+          aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
+        } else
+        if (bxm < axm && bym >= aym)    // 11.
+        {
+          aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
+          aResult.InsertInPlace (new RgnRect (ixm, iy, axm - ixm, ih));
+        } else
+        if (bxm >= axm && bym >= aym)   // 12.
+        {
+          aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
+        }
+      } else
+      if (bx > ax && by > ay)
+      {
+        if (bxm < axm && bym < aym)     // 13.
+        {
+          aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
+          aResult.InsertInPlace (new RgnRect (ax, iy, ix - ax, ih));
+          aResult.InsertInPlace (new RgnRect (ixm, iy, axm - ixm, ih));
+          aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
+
+          // Current rectangle fully overlays aRect. No any other rectangle can intersect it.
+          pSrcRect = pSrcRect->next;    // don't add this one to the result, it's removed
+          break;
+        } else
+        if (bxm >= axm && bym < aym)    // 14.
+        {
+          aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
+          aResult.InsertInPlace (new RgnRect (ax, iy, ix - ax, ih));
+          aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
+        } else
+        if (bxm < axm && bym >= aym)    // 15.
+        {
+          aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
+          aResult.InsertInPlace (new RgnRect (ax, iy, ix - ax, ih));
+          aResult.InsertInPlace (new RgnRect (ixm, iy, axm - ixm, ih));
+        } else
+        if (bxm >= axm && bym >= aym)   // 16.
+        {
+          aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
+          aResult.InsertInPlace (new RgnRect (ax, iy, ix - ax, ih));
+        }
+      }
     }
   }
 
-  uint32_t reducedCount = dest+1;
-  // pixman has a special representation for
-  // regions of 1 rectangle. So just use the
-  // bounds in that case
-  if (reducedCount > 1 && reducedCount <= aMaxRects) {
-    // reach into pixman and lower the number
-    // of rects stored in data.
-    mImpl.data->numRects = reducedCount;
-  } else {
-    *this = GetBounds();
+  // Just copy remaining rectangles in region which are below aRect and can't intersect it.
+  // If rectangles are in temporary region then they could be moved.
+  if (pSrcRegion == &TmpRegion)
+    TmpRegion.MoveInto (aResult, pSrcRect);
+  else
+  {
+    while (pSrcRect != &pSrcRegion->mRectListHead)
+    {
+      aResult.InsertInPlace (new RgnRect (*pSrcRect));
+      pSrcRect = pSrcRect->next;
+    }
   }
 }
 
-void nsRegion::SimplifyInward (uint32_t aMaxRects)
+
+bool nsRegion::IsEqual (const nsRegion& aRegion) const
 {
-  NS_ASSERTION(aMaxRects >= 1, "Invalid max rect count");
+  if (mRectCount == 0)
+    return (aRegion.mRectCount == 0) ? true : false;
+
+  if (aRegion.mRectCount == 0)
+    return (mRectCount == 0) ? true : false;
 
-  if (GetNumRects() <= aMaxRects)
-    return;
+  if (mRectCount == 1 && aRegion.mRectCount == 1) // Both regions are simple rectangles
+    return (mRectListHead.next->IsEqualInterior(*aRegion.mRectListHead.next));
+  else                                            // At least one is complex region.
+  {
+    if (!mBoundRect.IsEqualInterior(aRegion.mBoundRect)) // If regions are equal then bounding rectangles should match
+      return false;
+    else
+    {
+      nsRegion TmpRegion;
+      TmpRegion.Xor (*this, aRegion);             // Get difference between two regions
 
-  SetEmpty();
+      return (TmpRegion.mRectCount == 0);
+    }
+  }
 }
 
+
 uint64_t nsRegion::Area () const
 {
   uint64_t area = 0;
   nsRegionRectIterator iter(*this);
   const nsRect* r;
   while ((r = iter.Next()) != nullptr) {
     area += uint64_t(r->width)*r->height;
   }
   return area;
 }
 
+
+void nsRegion::MoveBy (nsPoint aPt)
+{
+  if (aPt.x || aPt.y)
+  {
+    RgnRect* pRect = mRectListHead.next;
+
+    while (pRect != &mRectListHead)
+    {
+      pRect->MoveBy (aPt.x, aPt.y);
+      pRect = pRect->next;
+    }
+
+    mBoundRect.MoveBy (aPt.x, aPt.y);
+  }
+}
+
 nsRegion& nsRegion::ScaleRoundOut (float aXScale, float aYScale)
 {
-  int n;
-  pixman_box32_t *boxes = pixman_region32_rectangles(&mImpl, &n);
-  for (int i=0; i<n; i++) {
-    nsRect rect = BoxToRect(boxes[i]);
+  nsRegion region;
+  nsRegionRectIterator iter(*this);
+  for (;;) {
+    const nsRect* r = iter.Next();
+    if (!r)
+      break;
+    nsRect rect = *r;
     rect.ScaleRoundOut(aXScale, aYScale);
-    boxes[i] = RectToBox(rect);
+    region.Or(region, rect);
   }
-
-  pixman_region32_t region;
-  // This will union all of the rectangles and runs in about O(n lg(n))
-  pixman_region32_init_rects(&region, boxes, n);
-
-  pixman_region32_fini(&mImpl);
-  mImpl = region;
+  *this = region;
   return *this;
 }
 
 nsRegion& nsRegion::ScaleInverseRoundOut (float aXScale, float aYScale)
 {
-  int n;
-  pixman_box32_t *boxes = pixman_region32_rectangles(&mImpl, &n);
-  for (int i=0; i<n; i++) {
-    nsRect rect = BoxToRect(boxes[i]);
+  nsRegion region;
+  nsRegionRectIterator iter(*this);
+  for (;;) {
+    const nsRect* r = iter.Next();
+    if (!r)
+      break;
+    nsRect rect = *r;
     rect.ScaleInverseRoundOut(aXScale, aYScale);
-    boxes[i] = RectToBox(rect);
+    region.Or(region, rect);
   }
+  *this = region;
+  return *this;
+}
 
-  pixman_region32_t region;
-  // This will union all of the rectangles and runs in about O(n lg(n))
-  pixman_region32_init_rects(&region, boxes, n);
-
-  pixman_region32_fini(&mImpl);
-  mImpl = region;
-  return *this;
+void nsRegion::Inflate(const nsMargin& aMargin)
+{
+  nsRegion region;
+  nsRegionRectIterator iter(*this);
+  for (;;) {
+    const nsRect* r = iter.Next();
+    if (!r)
+      break;
+    nsRect rect = *r;
+    rect.Inflate(aMargin);
+    region.Or(region, rect);
+  }
+  *this = region;
 }
 
 nsRegion nsRegion::ConvertAppUnitsRoundOut (int32_t aFromAPP, int32_t aToAPP) const
 {
   if (aFromAPP == aToAPP) {
     return *this;
   }
-
-  nsRegion region = *this;
-  int n;
-  pixman_box32_t *boxes = pixman_region32_rectangles(&region.mImpl, &n);
-  for (int i=0; i<n; i++) {
-    nsRect rect = BoxToRect(boxes[i]);
-    rect = rect.ConvertAppUnitsRoundOut(aFromAPP, aToAPP);
-    boxes[i] = RectToBox(rect);
+  // Do it in a simplistic and slow way to avoid any weird behaviour with
+  // rounding causing rects to overlap. Should be fast enough for what we need.
+  nsRegion region;
+  nsRegionRectIterator iter(*this);
+  for (;;) {
+    const nsRect* r = iter.Next();
+    if (!r)
+      break;
+    nsRect rect = r->ConvertAppUnitsRoundOut(aFromAPP, aToAPP);
+    region.Or(region, rect);
   }
-
-  pixman_region32_t pixmanRegion;
-  // This will union all of the rectangles and runs in about O(n lg(n))
-  pixman_region32_init_rects(&pixmanRegion, boxes, n);
-
-  pixman_region32_fini(&region.mImpl);
-  region.mImpl = pixmanRegion;
   return region;
 }
 
 nsRegion nsRegion::ConvertAppUnitsRoundIn (int32_t aFromAPP, int32_t aToAPP) const
 {
   if (aFromAPP == aToAPP) {
     return *this;
   }
-
-  nsRegion region = *this;
-  int n;
-  pixman_box32_t *boxes = pixman_region32_rectangles(&region.mImpl, &n);
-  for (int i=0; i<n; i++) {
-    nsRect rect = BoxToRect(boxes[i]);
-    rect = rect.ConvertAppUnitsRoundIn(aFromAPP, aToAPP);
-    boxes[i] = RectToBox(rect);
+  // Do it in a simplistic and slow way to avoid any weird behaviour with
+  // rounding causing rects to overlap. Should be fast enough for what we need.
+  nsRegion region;
+  nsRegionRectIterator iter(*this);
+  for (;;) {
+    const nsRect* r = iter.Next();
+    if (!r)
+      break;
+    nsRect rect = r->ConvertAppUnitsRoundIn(aFromAPP, aToAPP);
+    region.Or(region, rect);
   }
-
-  pixman_region32_t pixmanRegion;
-  // This will union all of the rectangles and runs in about O(n lg(n))
-  pixman_region32_init_rects(&pixmanRegion, boxes, n);
-
-  pixman_region32_fini(&region.mImpl);
-  region.mImpl = pixmanRegion;
   return region;
 }
 
 nsIntRegion nsRegion::ToPixels (nscoord aAppUnitsPerPixel, bool aOutsidePixels) const
 {
-  nsRegion region = *this;
-  int n;
-  pixman_box32_t *boxes = pixman_region32_rectangles(&region.mImpl, &n);
-  for (int i=0; i<n; i++) {
-    nsRect rect = BoxToRect(boxes[i]);
+  nsIntRegion result;
+  nsRegionRectIterator rgnIter(*this);
+  const nsRect* currentRect;
+  while ((currentRect = rgnIter.Next())) {
     nsIntRect deviceRect;
     if (aOutsidePixels)
-      deviceRect = rect.ToOutsidePixels(aAppUnitsPerPixel);
+      deviceRect = currentRect->ToOutsidePixels(aAppUnitsPerPixel);
     else
-      deviceRect = rect.ToNearestPixels(aAppUnitsPerPixel);
-
-    boxes[i] = RectToBox(deviceRect);
+      deviceRect = currentRect->ToNearestPixels(aAppUnitsPerPixel);
+    result.Or(result, deviceRect);
   }
-
-  nsIntRegion intRegion;
-  pixman_region32_fini(&intRegion.mImpl.mImpl);
-  // This will union all of the rectangles and runs in about O(n lg(n))
-  pixman_region32_init_rects(&intRegion.mImpl.mImpl, boxes, n);
-
-  return intRegion;
+  return result;
 }
 
 nsIntRegion nsRegion::ToOutsidePixels (nscoord aAppUnitsPerPixel) const
 {
   return ToPixels(aAppUnitsPerPixel, true);
 }
 
 nsIntRegion nsRegion::ToNearestPixels (nscoord aAppUnitsPerPixel) const
@@ -277,67 +1456,59 @@ nsIntRegion nsRegion::ScaleToInsidePixel
    *
    * If it is, then the contained edge can be moved (in scaled pixels) to ensure that no
    * gap exists.
    *
    * Since this could be potentially expensive - O(n^2), we only attempt this algorithm
    * for the first rect.
    */
 
-  // make a copy of this region so that we can mutate it in place
-  nsRegion region = *this;
-  int n;
-  pixman_box32_t *boxes = pixman_region32_rectangles(&region.mImpl, &n);
+  nsIntRegion result;
+  RgnRect* pRect = mRectListHead.next;
+  RgnRect* first = pRect;
 
-  nsIntRegion intRegion;
-  if (n) {
-    nsRect first = BoxToRect(boxes[0]);
-    nsIntRect firstDeviceRect =
-      first.ScaleToInsidePixels(aScaleX, aScaleY, aAppUnitsPerPixel);
+  nsIntRect firstDeviceRect;
+  if (pRect != &mRectListHead) {
+    firstDeviceRect =
+      pRect->ScaleToInsidePixels(aScaleX, aScaleY, aAppUnitsPerPixel);
+    pRect = pRect->next;
+  }
 
-    for (int i=1; i<n; i++) {
-      nsRect rect = nsRect(boxes[i].x1, boxes[i].y1,
-	  boxes[i].x2 - boxes[i].x1,
-	  boxes[i].y2 - boxes[i].y1);
-      nsIntRect deviceRect =
-	rect.ScaleToInsidePixels(aScaleX, aScaleY, aAppUnitsPerPixel);
+  while (pRect != &mRectListHead)
+  {
+    nsIntRect deviceRect =
+      pRect->ScaleToInsidePixels(aScaleX, aScaleY, aAppUnitsPerPixel);
 
-      if (rect.y <= first.YMost()) {
-	if (rect.XMost() == first.x && rect.YMost() <= first.YMost()) {
-	  // rect is touching on the left edge of the first rect and contained within
-	  // the length of its left edge
-	  deviceRect.SetRightEdge(firstDeviceRect.x);
-	} else if (rect.x == first.XMost() && rect.YMost() <= first.YMost()) {
-	  // rect is touching on the right edge of the first rect and contained within
-	  // the length of its right edge
-	  deviceRect.SetLeftEdge(firstDeviceRect.XMost());
-	} else if (rect.y == first.YMost()) {
-	  // The bottom of the first rect is on the same line as the top of rect, but
-	  // they aren't necessarily contained.
-	  if (rect.x <= first.x && rect.XMost() >= first.XMost()) {
-	    // The top of rect contains the bottom of the first rect
-	    firstDeviceRect.SetBottomEdge(deviceRect.y);
-	  } else if (rect.x >= first.x && rect.XMost() <= first.XMost()) {
-	    // The bottom of the first contains the top of rect
-	    deviceRect.SetTopEdge(firstDeviceRect.YMost());
-	  }
-	}
+    if (pRect->y <= first->YMost()) {
+      if (pRect->XMost() == first->x && pRect->YMost() <= first->YMost()) {
+        // pRect is touching on the left edge of the first rect and contained within
+        // the length of its left edge
+        deviceRect.SetRightEdge(firstDeviceRect.x);
+      } else if (pRect->x == first->XMost() && pRect->YMost() <= first->YMost()) {
+        // pRect is touching on the right edge of the first rect and contained within
+        // the length of its right edge
+        deviceRect.SetLeftEdge(firstDeviceRect.XMost());
+      } else if (pRect->y == first->YMost()) {
+        // The bottom of the first rect is on the same line as the top of pRect, but 
+        // they aren't necessarily contained.
+        if (pRect->x <= first->x && pRect->XMost() >= first->XMost()) {
+          // The top of pRect contains the bottom of the first rect
+          firstDeviceRect.SetBottomEdge(deviceRect.y);
+        } else if (pRect->x >= first->x && pRect->XMost() <= first->XMost()) {
+          // The bottom of the first contains the top of pRect
+          deviceRect.SetTopEdge(firstDeviceRect.YMost());
+        }
       }
-
-      boxes[i] = RectToBox(deviceRect);
     }
-
-    boxes[0] = RectToBox(firstDeviceRect);
+    pRect = pRect->next;
+    result.Or(result, deviceRect);
+  }
 
-    pixman_region32_fini(&intRegion.mImpl.mImpl);
-    // This will union all of the rectangles and runs in about O(n lg(n))
-    pixman_region32_init_rects(&intRegion.mImpl.mImpl, boxes, n);
-  }
-  return intRegion;
-
+  result.Or(result, firstDeviceRect);
+  return result;
 }
 
 // A cell's "value" is a pair consisting of
 // a) the area of the subrectangle it corresponds to, if it's in
 // aContainingRect and in the region, 0 otherwise
 // b) the area of the subrectangle it corresponds to, if it's in the region,
 // 0 otherwise
 // Addition, subtraction and identity are defined on these values in the
@@ -526,18 +1697,18 @@ namespace {
 
     return max;
   }
 }
 
 nsRect nsRegion::GetLargestRectangle (const nsRect& aContainingRect) const {
   nsRect bestRect;
 
-  if (GetNumRects() <= 1) {
-    bestRect = GetBounds();
+  if (mRectCount <= 1) {
+    bestRect = mBoundRect;
     return bestRect;
   }
 
   AxisPartition xaxis, yaxis;
 
   // Step 1: Calculate the grid lines
   nsRegionRectIterator iter(*this);
   const nsRect *currentRect;
@@ -633,35 +1804,120 @@ nsRect nsRegion::GetLargestRectangle (co
                     yaxis.StopAt(bestRectIndices.top));
     bestRect.SizeTo(xaxis.StopAt(bestRectIndices.right) - bestRect.x,
                     yaxis.StopAt(bestRectIndices.bottom) - bestRect.y);
   }
 
   return bestRect;
 }
 
-nsCString
-nsRegion::ToString() const {
-    nsCString result;
-    result.AppendLiteral("[");
+void nsRegion::SimplifyOutward (uint32_t aMaxRects)
+{
+  NS_ASSERTION(aMaxRects >= 1, "Invalid max rect count");
+  
+  if (mRectCount <= aMaxRects)
+    return;
 
-    int n;
-    pixman_box32_t *boxes = pixman_region32_rectangles(const_cast<pixman_region32_t*>(&mImpl), &n);
-    for (int i=0; i<n; i++) {
-        if (i != 0) {
-            result.AppendLiteral("; ");
-        }
-        result.Append(nsPrintfCString("%d,%d,%d,%d", boxes[i].x1, boxes[i].y1, boxes[i].x2, boxes[i].y2));
+  // Try combining rects in horizontal bands into a single rect
+  RgnRect* pRect = mRectListHead.next;
+  while (pRect != &mRectListHead)
+  {
+    // Combine with the following rectangle if they have the same YMost
+    // or if they overlap vertically. This ensures that all overlapping
+    // rectangles are merged, preserving the invariant that rectangles
+    // don't overlap.
+    // The goal here is to try to keep groups of rectangles that are vertically
+    // discontiguous as separate rectangles in the final region. This is
+    // simple and fast to implement and page contents tend to vary more
+    // vertically than horizontally (which is why our rectangles are stored
+    // sorted by y-coordinate, too).
+    while (pRect->next != &mRectListHead &&
+           pRect->YMost () >= pRect->next->y)
+    {
+      pRect->UnionRect(*pRect, *pRect->next);
+      delete Remove (pRect->next);
+    }
 
-    }
-    result.AppendLiteral("]");
+    pRect = pRect->next;
+  }
+
+  if (mRectCount <= aMaxRects)
+    return;
+
+  *this = GetBounds();
+}
 
-    return result;
+void nsRegion::SimplifyInward (uint32_t aMaxRects)
+{
+  NS_ASSERTION(aMaxRects >= 1, "Invalid max rect count");
+
+  if (mRectCount <= aMaxRects)
+    return;
+
+  SetEmpty();
 }
 
+void nsRegion::SimpleSubtract (const nsRect& aRect)
+{
+  if (aRect.IsEmpty())
+    return;
+
+  // protect against aRect being one of our own rectangles
+  nsRect param = aRect;
+  RgnRect* r = mRectListHead.next;
+  while (r != &mRectListHead)
+  {
+    RgnRect* next = r->next;
+    if (param.Contains(*r)) {
+      delete Remove(r);
+    }
+    r = next;
+  }
+  
+  Optimize();
+}
+
+void nsRegion::SimpleSubtract (const nsRegion& aRegion)
+{
+  if (aRegion.IsEmpty())
+    return;
+
+  if (&aRegion == this) {
+    SetEmpty();
+    return;
+  }
+
+  const RgnRect* r = aRegion.mRectListHead.next;
+  while (r != &aRegion.mRectListHead)
+  {
+    SimpleSubtract(*r);
+    r = r->next;
+  }
+
+  Optimize();
+}
+
+nsCString
+nsRegion::ToString() const
+{
+  nsCString result;
+  result.AppendLiteral("[");
+  const RgnRect* r = mRectListHead.next;
+  while (r != &mRectListHead)
+  {
+    if (r != mRectListHead.next) {
+      result.AppendLiteral("; ");
+    }
+    result.Append(nsPrintfCString("%d,%d,%d,%d", r->x, r->y, r->XMost(), r->YMost()));
+    r = r->next;
+  }
+  result.AppendLiteral("]");
+
+  return result;
+}
 
 nsRegion nsIntRegion::ToAppUnits (nscoord aAppUnitsPerPixel) const
 {
   nsRegion result;
   nsIntRegionRectIterator rgnIter(*this);
   const nsIntRect* currentRect;
   while ((currentRect = rgnIter.Next())) {
     nsRect appRect = currentRect->ToAppUnits(aAppUnitsPerPixel);
--- a/gfx/src/nsRegion.h
+++ b/gfx/src/nsRegion.h
@@ -15,165 +15,144 @@
 #include "nsPoint.h"                    // for nsIntPoint, nsPoint
 #include "nsRect.h"                     // for nsIntRect, nsRect
 #include "nsMargin.h"                   // for nsIntMargin
 #include "nsString.h"               // for nsCString
 #include "xpcom-config.h"               // for CPP_THROW_NEW
 
 class nsIntRegion;
 
-#include "pixman.h"
-
-/* For information on the internal representation look at pixman-region.c
+/**
+ * Implementation of regions.
+ * A region is represented as circular double-linked list of nsRegion::RgnRect structures.
+ * Rectangles in this list do not overlap and are sorted by (y, x) coordinates.
  *
- * This replaces an older homebrew implementation of nsRegion. The
- * representation used here may use more rectangles than nsRegion however, the
- * representation is canonical.  This means that there's no need for an
- * Optimize() method because for a paticular region there is only one
- * representation. This means that nsIntRegion will have more predictable
- * performance characteristics than the old nsRegion and should not become
- * degenerate.
- *
- * The pixman region code originates from X11 which has spread to a variety of
- * projects including Qt, Gtk, Wine. It should perform reasonably well.
+ * nsRegions use nscoord coordinates and nsRects.
  */
+class NS_GFX nsRegion
+{
+  friend class nsRegionRectIterator;
+  friend class RgnRectMemoryAllocator;
 
-class nsRegionRectIterator;
+
+// Special version of nsRect structure for speed optimizations in nsRegion code.
+// Most important functions could be made inline and be sure that passed rectangles
+// will always be non-empty.
+// 
+// Do not add any new member variables to this structure! 
+// Otherwise it will break casts from nsRect to nsRectFast, which expect data parts to be identical.
+  struct nsRectFast : public nsRect
+  {
+    nsRectFast () {}      // No need to call parent constructor to set default values
+    nsRectFast (int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight) : nsRect (aX, aY, aWidth, aHeight) {}
+    nsRectFast (const nsRect& aRect) : nsRect (aRect) {}
 
-class nsRegion
-{
+    // Override nsRect methods to make them inline. Do not check for emptiness.
+    inline bool Contains (const nsRect& aRect) const;
+    inline bool Intersects (const nsRect& aRect) const;
+    inline bool IntersectRect (const nsRect& aRect1, const nsRect& aRect2);
+    inline void UnionRect (const nsRect& aRect1, const nsRect& aRect2);
+  };
+
+
+  struct RgnRect : public nsRectFast
+  {
+    RgnRect* prev;
+    RgnRect* next;
 
-  friend class nsRegionRectIterator;
+    RgnRect () {}                           // No need to call parent constructor to set default values
+    RgnRect (int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight) : nsRectFast (aX, aY, aWidth, aHeight) {}
+    RgnRect (const nsRectFast& aRect) : nsRectFast (aRect) {}
+
+    void* operator new (size_t) CPP_THROW_NEW;
+    void  operator delete (void* aRect, size_t);
+
+    RgnRect& operator = (const RgnRect& aRect)      // Do not overwrite prev/next pointers
+    {
+      x = aRect.x;
+      y = aRect.y;
+      width = aRect.width;
+      height = aRect.height;
+      return *this;
+    }
+  };
+
 
 public:
-  nsRegion () { pixman_region32_init(&mImpl); }
-  nsRegion (const nsRect& aRect) { pixman_region32_init_rect(&mImpl,
-                                                                    aRect.x,
-                                                                    aRect.y,
-                                                                    aRect.width,
-                                                                    aRect.height); }
-  nsRegion (const nsRegion& aRegion) { pixman_region32_init(&mImpl); pixman_region32_copy(&mImpl,aRegion.Impl()); }
- ~nsRegion () { pixman_region32_fini(&mImpl); }
+  nsRegion () { Init (); }
+  nsRegion (const nsRect& aRect) { Init (); Copy (aRect); }
+  nsRegion (const nsRegion& aRegion) { Init (); Copy (aRegion); }
+ ~nsRegion () { SetToElements (0); }
   nsRegion& operator = (const nsRect& aRect) { Copy (aRect); return *this; }
   nsRegion& operator = (const nsRegion& aRegion) { Copy (aRegion); return *this; }
-  bool operator==(const nsRegion& aRgn) const
-  {
-    return IsEqual(aRgn);
-  }
 
-  static
-  nsresult InitStatic()
-  {
-    return NS_OK;
-  }
-
-  static
-  void ShutdownStatic() {}
 
-  nsRegion& And(const nsRegion& aRgn1,   const nsRegion& aRgn2)
-  {
-    pixman_region32_intersect(&mImpl, aRgn1.Impl(), aRgn2.Impl());
-    return *this;
-  }
-  nsRegion& And(const nsRect& aRect, const nsRegion& aRegion)
+  nsRegion& And  (const nsRegion& aRgn1,   const nsRegion& aRgn2);
+  nsRegion& And  (const nsRegion& aRegion, const nsRect& aRect);
+  nsRegion& And  (const nsRect& aRect, const nsRegion& aRegion)
   {
-    return And(aRegion, aRect);
+    return  And  (aRegion, aRect);
   }
-  nsRegion& And(const nsRegion& aRegion, const nsRect& aRect)
-  {
-    pixman_region32_intersect_rect(&mImpl, aRegion.Impl(), aRect.x, aRect.y, aRect.width, aRect.height);
-    return *this;
-  }
-  nsRegion& And(const nsRect& aRect1, const nsRect& aRect2)
+  nsRegion& And  (const nsRect& aRect1, const nsRect& aRect2)
   {
     nsRect TmpRect;
 
-    TmpRect.IntersectRect(aRect1, aRect2);
-    return Copy(TmpRect);
+    TmpRect.IntersectRect (aRect1, aRect2);
+    return Copy (TmpRect);
   }
 
-  nsRegion& Or(const nsRegion& aRgn1, const nsRegion& aRgn2)
-  {
-    pixman_region32_union(&mImpl, aRgn1.Impl(), aRgn2.Impl());
-    return *this;
-  }
-  nsRegion& Or(const nsRegion& aRegion, const nsRect& aRect)
+  nsRegion& Or   (const nsRegion& aRgn1,   const nsRegion& aRgn2);
+  nsRegion& Or   (const nsRegion& aRegion, const nsRect& aRect);
+  nsRegion& Or   (const nsRect& aRect, const nsRegion& aRegion)
   {
-    pixman_region32_union_rect(&mImpl, aRegion.Impl(), aRect.x, aRect.y, aRect.width, aRect.height);
-    return *this;
+    return  Or   (aRegion, aRect);
   }
-  nsRegion& Or(const nsRect& aRect, const nsRegion& aRegion)
-  {
-    return  Or(aRegion, aRect);
-  }
-  nsRegion& Or(const nsRect& aRect1, const nsRect& aRect2)
+  nsRegion& Or   (const nsRect& aRect1, const nsRect& aRect2)
   {
     Copy (aRect1);
     return Or (*this, aRect2);
   }
 
-  nsRegion& Xor(const nsRegion& aRgn1,   const nsRegion& aRgn2)
+  nsRegion& Xor  (const nsRegion& aRgn1,   const nsRegion& aRgn2);
+  nsRegion& Xor  (const nsRegion& aRegion, const nsRect& aRect);
+  nsRegion& Xor  (const nsRect& aRect, const nsRegion& aRegion)
   {
-    // this could be implemented better if pixman had direct
-    // support for xoring regions.
-    nsRegion p;
-    p.Sub(aRgn1, aRgn2);
-    nsRegion q;
-    q.Sub(aRgn2, aRgn1);
-    return Or(p, q);
+    return  Xor  (aRegion, aRect);
   }
-  nsRegion& Xor(const nsRegion& aRegion, const nsRect& aRect)
-  {
-    return Xor(aRegion, nsRegion(aRect));
-  }
-  nsRegion& Xor(const nsRect& aRect, const nsRegion& aRegion)
+  nsRegion& Xor  (const nsRect& aRect1, const nsRect& aRect2)
   {
-    return Xor(nsRegion(aRect), aRegion);
-  }
-  nsRegion& Xor(const nsRect& aRect1, const nsRect& aRect2)
-  {
-    return Xor(nsRegion(aRect1), nsRegion(aRect2));
+    Copy (aRect1);
+    return Xor (*this, aRect2);
   }
 
-  nsRegion ToAppUnits (nscoord aAppUnitsPerPixel) const;
-  nsRegion& Sub(const nsRegion& aRgn1, const nsRegion& aRgn2)
-  {
-    pixman_region32_subtract(&mImpl, aRgn1.Impl(), aRgn2.Impl());
-    return *this;
-  }
-  nsRegion& Sub(const nsRegion& aRegion, const nsRect& aRect)
+  nsRegion& Sub  (const nsRegion& aRgn1,   const nsRegion& aRgn2);
+  nsRegion& Sub  (const nsRegion& aRegion, const nsRect& aRect);
+  nsRegion& Sub  (const nsRect& aRect, const nsRegion& aRegion)
   {
-    return Sub(aRegion, nsRegion(aRect));
+    return Sub (nsRegion (aRect), aRegion);
   }
-  nsRegion& Sub(const nsRect& aRect, const nsRegion& aRegion)
+  nsRegion& Sub  (const nsRect& aRect1, const nsRect& aRect2)
   {
-    return Sub(nsRegion(aRect), aRegion);
-  }
-  nsRegion& Sub(const nsRect& aRect1, const nsRect& aRect2)
-  {
-    Copy(aRect1);
-    return Sub(*this, aRect2);
+    Copy (aRect1);
+    return Sub (*this, aRect2);
   }
 
-  bool Contains (const nsRect& aRect) const
-  {
-    pixman_box32_t box = RectToBox(aRect);
-    return pixman_region32_contains_rectangle(Impl(), &box) == PIXMAN_REGION_IN;
-  }
+  bool Contains (const nsRect& aRect) const;
   bool Contains (const nsRegion& aRgn) const;
   bool Intersects (const nsRect& aRect) const;
 
   void MoveBy (int32_t aXOffset, int32_t aYOffset)
   {
     MoveBy (nsPoint (aXOffset, aYOffset));
   }
-  void MoveBy (nsPoint aPt) { pixman_region32_translate(&mImpl, aPt.x, aPt.y); }
+  void MoveBy (nsPoint aPt);
   void SetEmpty ()
   {
-    pixman_region32_clear(&mImpl);
+    SetToElements (0);
+    mBoundRect.SetRect (0, 0, 0, 0);
   }
 
   nsRegion MovedBy(int32_t aXOffset, int32_t aYOffset) const
   {
     return MovedBy(nsPoint(aXOffset, aYOffset));
   }
   nsRegion MovedBy(const nsPoint& aPt) const
   {
@@ -193,24 +172,21 @@ public:
 
   nsRegion Inflated(const nsMargin& aMargin) const
   {
     nsRegion copy(*this);
     copy.Inflate(aMargin);
     return copy;
   }
 
-  bool IsEmpty () const { return !pixman_region32_not_empty(Impl()); }
-  bool IsComplex () const { return GetNumRects() > 1; }
-  bool IsEqual (const nsRegion& aRegion) const
-  {
-    return pixman_region32_equal(Impl(), aRegion.Impl());
-  }
-  uint32_t GetNumRects () const { return pixman_region32_n_rects(Impl()); }
-  const nsRect GetBounds () const { return BoxToRect(mImpl.extents); }
+  bool IsEmpty () const { return mRectCount == 0; }
+  bool IsComplex () const { return mRectCount > 1; }
+  bool IsEqual (const nsRegion& aRegion) const;
+  uint32_t GetNumRects () const { return mRectCount; }
+  const nsRect& GetBounds () const { return mBoundRect; }
   uint64_t Area () const;
   // Converts this region from aFromAPP, an appunits per pixel ratio, to
   // aToAPP. This applies nsRect::ConvertAppUnitsRoundOut/In to each rect of
   // the region.
   nsRegion ConvertAppUnitsRoundOut (int32_t aFromAPP, int32_t aToAPP) const;
   nsRegion ConvertAppUnitsRoundIn (int32_t aFromAPP, int32_t aToAPP) const;
   nsRegion& ScaleRoundOut(float aXScale, float aYScale);
   nsRegion& ScaleInverseRoundOut(float aXScale, float aYScale);
@@ -236,111 +212,114 @@ public:
    */
   void SimplifyOutward (uint32_t aMaxRects);
   /**
    * Make sure the region has at most aMaxRects by removing area from
    * it if necessary. The simplified region will be a subset of the
    * original region.
    */
   void SimplifyInward (uint32_t aMaxRects);
+  /**
+   * Efficiently try to remove a rectangle from this region. The actual
+   * area removed could be some sub-area contained by the rectangle
+   * (even possibly nothing at all).
+   * 
+   * We remove all rectangles that are contained by aRect.
+   */
+  void SimpleSubtract (const nsRect& aRect);
+  /**
+   * Efficiently try to remove a region from this region. The actual
+   * area removed could be some sub-area contained by aRegion
+   * (even possibly nothing at all).
+   * 
+   * We remove all rectangles of this region that are contained by
+   * a rectangle of aRegion.
+   */
+  void SimpleSubtract (const nsRegion& aRegion);
 
   nsCString ToString() const;
-private:
-  pixman_region32_t mImpl;
 
-  nsIntRegion ToPixels(nscoord aAppUnitsPerPixel, bool aOutsidePixels) const;
+  /**
+   * Initialize any static data associated with nsRegion.
+   */
+  static nsresult InitStatic();
 
-  nsRegion& Copy (const nsRegion& aRegion)
-  {
-    pixman_region32_copy(&mImpl, aRegion.Impl());
-    return *this;
-  }
+  /**
+   * Deinitialize static data.
+   */
+  static void ShutdownStatic();
+
+private:
+  uint32_t    mRectCount;
+  RgnRect*    mCurRect;
+  RgnRect     mRectListHead;
+  nsRectFast  mBoundRect;
 
-  nsRegion& Copy (const nsRect& aRect)
-  {
-    pixman_box32_t box = RectToBox(aRect);
-    pixman_region32_reset(&mImpl, &box);
-    return *this;
-  }
-
-  static inline pixman_box32_t RectToBox(const nsRect &aRect)
-  {
-    pixman_box32_t box = { aRect.x, aRect.y, aRect.XMost(), aRect.YMost() };
-    return box;
-  }
-
-  static inline pixman_box32_t RectToBox(const nsIntRect &aRect)
-  {
-    pixman_box32_t box = { aRect.x, aRect.y, aRect.XMost(), aRect.YMost() };
-    return box;
-  }
+  void Init ();
+  nsRegion& Copy (const nsRegion& aRegion);
+  nsRegion& Copy (const nsRect& aRect);
+  void InsertBefore (RgnRect* aNewRect, RgnRect* aRelativeRect);
+  void InsertAfter (RgnRect* aNewRect, RgnRect* aRelativeRect);
+  void SetToElements (uint32_t aCount);
+  RgnRect* Remove (RgnRect* aRect);
+  void InsertInPlace (RgnRect* aRect, bool aOptimizeOnFly = false);
+  inline void SaveLinkChain ();
+  inline void RestoreLinkChain ();
+  void Optimize ();
+  void SubRegion (const nsRegion& aRegion, nsRegion& aResult) const;
+  void SubRect (const nsRectFast& aRect, nsRegion& aResult, nsRegion& aCompleted) const;
+  void SubRect (const nsRectFast& aRect, nsRegion& aResult) const
+  {    SubRect (aRect, aResult, aResult);  }
+  void Merge (const nsRegion& aRgn1, const nsRegion& aRgn2);
+  void MoveInto (nsRegion& aDestRegion, const RgnRect* aStartRect);
+  void MoveInto (nsRegion& aDestRegion)
+  {    MoveInto (aDestRegion, mRectListHead.next);  }
+  nsIntRegion ToPixels(nscoord aAppUnitsPerPixel, bool aOutsidePixels) const;
+};
 
 
-  static inline nsRect BoxToRect(const pixman_box32_t &aBox)
-  {
-    return nsRect(aBox.x1, aBox.y1,
-                  aBox.x2 - aBox.x1,
-                  aBox.y2 - aBox.y1);
-  }
 
-  pixman_region32_t* Impl() const
-  {
-    return const_cast<pixman_region32_t*>(&mImpl);
-  }
-
-};
-
+// Allow read-only access to region rectangles by iterating the list
 
 class NS_GFX nsRegionRectIterator
 {
   const nsRegion*  mRegion;
-  int i;
-  int n;
-  nsRect rect;
-  pixman_box32_t *boxes;
+  const nsRegion::RgnRect* mCurPtr;
 
 public:
   nsRegionRectIterator (const nsRegion& aRegion)
   {
     mRegion = &aRegion;
-    i = 0;
-    boxes = pixman_region32_rectangles(aRegion.Impl(), &n);
+    mCurPtr = &aRegion.mRectListHead;
   }
 
   const nsRect* Next ()
   {
-    if (i == n)
-      return nullptr;
-    rect = nsRegion::BoxToRect(boxes[i]);
-    i++;
-    return &rect;
+    mCurPtr = mCurPtr->next;
+    return (mCurPtr != &mRegion->mRectListHead) ? mCurPtr : nullptr;
   }
 
   const nsRect* Prev ()
   {
-    if (i == -1)
-      return nullptr;
-    rect = nsRegion::BoxToRect(boxes[i]);
-    i--;
-    return &rect;
+    mCurPtr = mCurPtr->prev;
+    return (mCurPtr != &mRegion->mRectListHead) ? mCurPtr : nullptr;
   }
 
   void Reset ()
   {
-    i = 0;
+    mCurPtr = &mRegion->mRectListHead;
   }
 };
 
 /**
  * nsIntRegions use int32_t coordinates and nsIntRects.
  */
 class NS_GFX nsIntRegion
 {
   friend class nsIntRegionRectIterator;
-  friend class nsRegion;
 
 public:
   nsIntRegion () {}
   nsIntRegion (const nsIntRect& aRect) : mImpl (ToRect(aRect)) {}
   nsIntRegion (const nsIntRegion& aRegion) : mImpl (aRegion.mImpl) {}
   nsIntRegion& operator = (const nsIntRect& aRect) { mImpl = ToRect (aRect); return *this; }
   nsIntRegion& operator = (const nsIntRegion& aRegion) { mImpl = aRegion.mImpl; return *this; }
 
@@ -522,16 +501,39 @@ public:
    * Make sure the region has at most aMaxRects by removing area from
    * it if necessary. The simplified region will be a subset of the
    * original region.
    */
   void SimplifyInward (uint32_t aMaxRects)
   {
     mImpl.SimplifyInward (aMaxRects);
   }
+  /**
+   * Efficiently try to remove a rectangle from this region. The actual
+   * area removed could be some sub-area contained by the rectangle
+   * (even possibly nothing at all).
+   * 
+   * We remove all rectangles that are contained by aRect.
+   */
+  void SimpleSubtract (const nsIntRect& aRect)
+  {
+    mImpl.SimpleSubtract (ToRect (aRect));
+  }
+  /**
+   * Efficiently try to remove a region from this region. The actual
+   * area removed could be some sub-area contained by aRegion
+   * (even possibly nothing at all).
+   * 
+   * We remove all rectangles of this region that are contained by
+   * a rectangle of aRegion.
+   */
+  void SimpleSubtract (const nsIntRegion& aRegion)
+  {
+    mImpl.SimpleSubtract (aRegion.mImpl);
+  }
 
   nsCString ToString() const { return mImpl.ToString(); }
 
 private:
   nsRegion mImpl;
 
   static nsRect ToRect(const nsIntRect& aRect)
   {
@@ -569,9 +571,10 @@ public:
     return &mTmp;
   }
 
   void Reset ()
   {
     mImpl.Reset ();
   }
 };
+
 #endif
--- a/gfx/tests/gtest/TestRegion.cpp
+++ b/gfx/tests/gtest/TestRegion.cpp
@@ -119,55 +119,8 @@ TEST(Gfx, RegionTwoRectTest) {
 TEST(Gfx, RegionContainsSpecifiedRect) {
   TestLargestRegion::TestContainsSpecifiedRect();
 }
 
 TEST(Gfx, RegionTestContainsSpecifiedOverflowingRect) {
   TestLargestRegion::TestContainsSpecifiedOverflowingRect();
 }
 
-TEST(Gfx, RegionScaleToInside) {
-  { // no rectangles
-    nsRegion r;
-
-    nsIntRegion scaled = r.ScaleToInsidePixels(1, 1, 60);
-    nsIntRegion result;
-
-    EXPECT_TRUE(result.IsEqual(scaled)) <<
-      "scaled result incorrect";
-  }
-
-  { // one rectangle
-    nsRegion r(nsRect(0,44760,19096,264));
-
-    nsIntRegion scaled = r.ScaleToInsidePixels(1, 1, 60);
-    nsIntRegion result(nsIntRect(0,746,318,4));
-
-    EXPECT_TRUE(result.IsEqual(scaled)) <<
-      "scaled result incorrect";
-  }
-
-
-  { // the first rectangle gets adjusted
-    nsRegion r(nsRect(0,44760,19096,264));
-    r.Or(r, nsRect(0,45024,19360,1056));
-
-    nsIntRegion scaled = r.ScaleToInsidePixels(1, 1, 60);
-    nsIntRegion result(nsIntRect(0,746,318,5));
-    result.Or(result, nsIntRect(0,751,322,17));
-
-    EXPECT_TRUE(result.IsEqual(scaled)) <<
-      "scaled result incorrect";
-  }
-
-  { // the second rectangle gets adjusted
-    nsRegion r(nsRect(0,44760,19360,264));
-    r.Or(r, nsRect(0,45024,19096,1056));
-
-    nsIntRegion scaled = r.ScaleToInsidePixels(1, 1, 60);
-    nsIntRegion result(nsIntRect(0,746,322,4));
-    result.Or(result, nsIntRect(0,750,318,18));
-
-    EXPECT_TRUE(result.IsEqual(scaled)) <<
-      "scaled result incorrect";
-  }
-
-}
--- a/layout/media/symbols.def.in
+++ b/layout/media/symbols.def.in
@@ -478,40 +478,16 @@ MOZ_XML_StopParser
 _moz_cairo_win32_surface_get_image
 #ifdef MOZ_TREE_PIXMAN
 _moz_pixman_image_composite32
 _moz_pixman_image_create_bits
 _moz_pixman_image_set_transform
 _moz_pixman_image_unref
 _moz_pixman_transform_from_pixman_f_transform
 _moz_pixman_transform_invert
-_moz_pixman_region32_reset
-_moz_pixman_region32_init
-_moz_pixman_region32_init_rect
-_moz_pixman_region32_init_rects
-_moz_pixman_region32_init_with_extents
-_moz_pixman_region32_fini
-_moz_pixman_region32_translate
-_moz_pixman_region32_copy
-_moz_pixman_region32_intersect
-_moz_pixman_region32_intersect_rect
-_moz_pixman_region32_union
-_moz_pixman_region32_union_rect
-_moz_pixman_region32_subtract
-_moz_pixman_region32_inverse
-_moz_pixman_region32_contains_point
-_moz_pixman_region32_contains_rectangle
-_moz_pixman_region32_not_empty
-_moz_pixman_region32_extents
-_moz_pixman_region32_n_rects
-_moz_pixman_region32_rectangles
-_moz_pixman_region32_equal
-_moz_pixman_region32_selfcheck
-_moz_pixman_region32_reset
-_moz_pixman_region32_clear
 #endif
 cairo_d2d_create_device
 cairo_d2d_create_device_from_d3d10device
 cairo_d2d_device_get_device
 cairo_d2d_get_dc
 cairo_d2d_get_image_surface_cache_usage
 cairo_d2d_get_surface_vram_usage
 cairo_d2d_present_backbuffer
--- a/uriloader/exthandler/Makefile.in
+++ b/uriloader/exthandler/Makefile.in
@@ -37,16 +37,16 @@ LOCAL_INCLUDES += -I$(topsrcdir)/dom/bas
             -I$(topsrcdir)/netwerk/base/src \
             -I$(topsrcdir)/netwerk/protocol/http
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 LOCAL_INCLUDES += -I$(srcdir)/win
 endif
 
 ifdef MOZ_ENABLE_DBUS
-OS_INCLUDES   += $(TK_CFLAGS) $(MOZ_DBUS_CFLAGS)
+LOCAL_INCLUDES   += $(TK_CFLAGS) $(MOZ_DBUS_CFLAGS)
 endif
 
 include $(topsrcdir)/config/rules.mk
 
 ifneq (,$(filter qt gtk2 gtk3, $(MOZ_WIDGET_TOOLKIT)))
 CXXFLAGS += $(TK_CFLAGS) $(MOZ_DBUS_GLIB_CFLAGS)
 endif