merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 29 Nov 2016 11:39:49 +0100
changeset 324483 f8107cf961444a8d7fdc2c0f446238af9893f875
parent 324398 15b774db7eab7fc4c9489db9c9f77a2e73536e22 (current diff)
parent 324482 2411fdf8a816414051e84cb2de43498d9e648d18 (diff)
child 324484 bc72fecfba2bacf52da6c98f6693548b2b4a0003
child 324601 d2870bba7114e3502026d4764b259b1f7c09cfdb
child 324632 782e8cbcc2c07889fe018ef160c2515558b615a8
push id31006
push usercbook@mozilla.com
push dateTue, 29 Nov 2016 10:40:01 +0000
treeherdermozilla-central@f8107cf96144 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone53.0a1
first release with
nightly linux32
f8107cf96144 / 53.0a1 / 20161129030222 / files
nightly linux64
f8107cf96144 / 53.0a1 / 20161129030222 / files
nightly mac
f8107cf96144 / 53.0a1 / 20161129030222 / files
nightly win32
f8107cf96144 / 53.0a1 / 20161129030222 / files
nightly win64
f8107cf96144 / 53.0a1 / 20161129030222 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
browser/themes/linux/webRTC-indicator.css
browser/themes/shared/webrtc/camera-white-16.png
browser/themes/shared/webrtc/camera-white-16@2x.png
browser/themes/shared/webrtc/microphone-white-16.png
browser/themes/shared/webrtc/microphone-white-16@2x.png
browser/themes/shared/webrtc/screen-white-16.png
browser/themes/shared/webrtc/screen-white-16@2x.png
browser/themes/windows/webRTC-indicator.css
gfx/thebes/PrintTargetCG.cpp
js/src/wasm/WasmGeneratedSourceMap.h
mfbt/Function.h
mfbt/tests/TestFunction.cpp
modules/libpref/init/all.js
netwerk/protocol/http/nsHttpChannel.cpp
testing/web-platform/meta/FileAPI/blob/Blob-slice.html.ini
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Merge day clobber
\ No newline at end of file
+Bug 1309272, part 5 renames gfx/thebes/PrintTargetCG.cpp (to .mm) which results in an object file of the same name, requiring a clobber.
--- a/browser/extensions/e10srollout/bootstrap.js
+++ b/browser/extensions/e10srollout/bootstrap.js
@@ -12,17 +12,17 @@ Cu.import("resource://gre/modules/Update
 
  // The amount of people to be part of e10s
 const TEST_THRESHOLD = {
   "beta"    : 0.5,  // 50%
   "release" : 1.0,  // 100%
 };
 
 const ADDON_ROLLOUT_POLICY = {
-  "beta"    : "51alladdons", // Any WebExtension or addon with mpc = true
+  "beta"    : "51alladdons", // Any WebExtension or addon except with mpc = false
   "release" : "50allmpc", // Any WebExtension or addon with mpc = true
 };
 
 const PREF_COHORT_SAMPLE       = "e10s.rollout.cohortSample";
 const PREF_COHORT_NAME         = "e10s.rollout.cohort";
 const PREF_E10S_OPTED_IN       = "browser.tabs.remote.autostart";
 const PREF_E10S_FORCE_ENABLED  = "browser.tabs.remote.force-enable";
 const PREF_E10S_FORCE_DISABLED = "browser.tabs.remote.force-disable";
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -401,16 +401,18 @@
 @RESPATH@/components/nsFilePicker.manifest
 @RESPATH@/components/nsFilePicker.js
 #endif
 @RESPATH@/components/nsHelperAppDlg.manifest
 @RESPATH@/components/nsHelperAppDlg.js
 @RESPATH@/components/NetworkGeolocationProvider.manifest
 @RESPATH@/components/NetworkGeolocationProvider.js
 @RESPATH@/components/extensions.manifest
+@RESPATH@/components/EditorUtils.manifest
+@RESPATH@/components/EditorUtils.js
 @RESPATH@/components/addonManager.js
 @RESPATH@/components/amContentHandler.js
 @RESPATH@/components/amInstallTrigger.js
 @RESPATH@/components/amWebAPI.js
 @RESPATH@/components/amWebInstallListener.js
 @RESPATH@/components/nsBlocklistService.js
 @RESPATH@/components/nsBlocklistServiceContent.js
 #ifdef MOZ_UPDATER
--- a/build/clang-plugin/tests/TestNoRefcountedInsideLambdas.cpp
+++ b/build/clang-plugin/tests/TestNoRefcountedInsideLambdas.cpp
@@ -1,10 +1,9 @@
 #include <functional>
-#include "mozilla/Function.h"
 #define MOZ_STRONG_REF __attribute__((annotate("moz_strong_ref")))
 
 struct RefCountedBase {
   void AddRef();
   void Release();
 };
 
 template <class T>
@@ -215,117 +214,16 @@ void b() {
   std::function<void(SmartPtr<R>)>([&sp](SmartPtr<R> argsp) {
     SmartPtr<R> localsp;
     take(sp);
     take(argsp);
     take(localsp);
   });
 }
 
-void c() {
-  R* ptr;
-  SmartPtr<R> sp;
-  mozilla::function<void(R*)>([&](R* argptr) {
-    R* localptr;
-    ptr->method();
-    argptr->method();
-    localptr->method();
-  });
-  mozilla::function<void(SmartPtr<R>)>([&](SmartPtr<R> argsp) {
-    SmartPtr<R> localsp;
-    sp->method();
-    argsp->method();
-    localsp->method();
-  });
-  mozilla::function<void(R*)>([&](R* argptr) {
-    R* localptr;
-    take(ptr);
-    take(argptr);
-    take(localptr);
-  });
-  mozilla::function<void(SmartPtr<R>)>([&](SmartPtr<R> argsp) {
-    SmartPtr<R> localsp;
-    take(sp);
-    take(argsp);
-    take(localsp);
-  });
-  mozilla::function<void(R*)>([=](R* argptr) {
-    R* localptr;
-    ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
-    argptr->method();
-    localptr->method();
-  });
-  mozilla::function<void(SmartPtr<R>)>([=](SmartPtr<R> argsp) {
-    SmartPtr<R> localsp;
-    sp->method();
-    argsp->method();
-    localsp->method();
-  });
-  mozilla::function<void(R*)>([=](R* argptr) {
-    R* localptr;
-    take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
-    take(argptr);
-    take(localptr);
-  });
-  mozilla::function<void(SmartPtr<R>)>([=](SmartPtr<R> argsp) {
-    SmartPtr<R> localsp;
-    take(sp);
-    take(argsp);
-    take(localsp);
-  });
-  mozilla::function<void(R*)>([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
-    R* localptr;
-    ptr->method();
-    argptr->method();
-    localptr->method();
-  });
-  mozilla::function<void(SmartPtr<R>)>([sp](SmartPtr<R> argsp) {
-    SmartPtr<R> localsp;
-    sp->method();
-    argsp->method();
-    localsp->method();
-  });
-  mozilla::function<void(R*)>([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
-    R* localptr;
-    take(ptr);
-    take(argptr);
-    take(localptr);
-  });
-  mozilla::function<void(SmartPtr<R>)>([sp](SmartPtr<R> argsp) {
-    SmartPtr<R> localsp;
-    take(sp);
-    take(argsp);
-    take(localsp);
-  });
-  mozilla::function<void(R*)>([&ptr](R* argptr) {
-    R* localptr;
-    ptr->method();
-    argptr->method();
-    localptr->method();
-  });
-  mozilla::function<void(SmartPtr<R>)>([&sp](SmartPtr<R> argsp) {
-    SmartPtr<R> localsp;
-    sp->method();
-    argsp->method();
-    localsp->method();
-  });
-  mozilla::function<void(R*)>([&ptr](R* argptr) {
-    R* localptr;
-    take(ptr);
-    take(argptr);
-    take(localptr);
-  });
-  mozilla::function<void(SmartPtr<R>)>([&sp](SmartPtr<R> argsp) {
-    SmartPtr<R> localsp;
-    take(sp);
-    take(argsp);
-    take(localsp);
-  });
-}
-
 // These tests would check c++14 deduced return types, if they were supported in
 // our codebase. They are being kept here for convenience in the future if we do
 // add support for c++14 deduced return types
 #if 0
 auto d1() {
   R* ptr;
   SmartPtr<R> sp;
   return ([&](R* argptr) {
--- a/build/moz.configure/rust.configure
+++ b/build/moz.configure/rust.configure
@@ -66,39 +66,46 @@ def rust_compiler(value, rustc, rustc_in
             version {} of the 'rustc' toolchain and make sure it is
             first in your path.
             You can verify this by typing 'rustc --version'.
             '''.format(version, min_version)))
         return True
 
 set_config('MOZ_RUST', rust_compiler)
 
-@depends(rust_compiler, rustc, target)
-@imports('os')
-@imports('subprocess')
-@imports(_from='mozbuild.configure.util', _import='LineIO')
-@imports(_from='mozbuild.shellutil', _import='quote')
-@imports(_from='tempfile', _import='mkstemp')
-def rust_target(rust_compiler, rustc, target):
-    if rust_compiler:
+@template
+def rust_triple_alias(host_or_target):
+    """Template defining the alias used for rustc's --target flag.
+    `host_or_target` is either `host` or `target` (the @depends functions
+    from init.configure).
+    """
+    assert host_or_target in (host, target)
+
+    @depends(rustc, host_or_target, when=rust_compiler)
+    @imports('os')
+    @imports('subprocess')
+    @imports(_from='mozbuild.configure.util', _import='LineIO')
+    @imports(_from='mozbuild.shellutil', _import='quote')
+    @imports(_from='tempfile', _import='mkstemp')
+    def rust_target(rustc, host_or_target):
         # Rust's --target options are similar to, but not exactly the same
         # as, the autoconf-derived targets we use.  An example would be that
         # Rust uses distinct target triples for targetting the GNU C++ ABI
         # and the MSVC C++ ABI on Win32, whereas autoconf has a single
         # triple and relies on the user to ensure that everything is
         # compiled for the appropriate ABI.  We need to perform appropriate
         # munging to get the correct option to rustc.
         #
         # The canonical list of targets supported can be derived from:
         #
         # https://github.com/rust-lang/rust/tree/master/mk/cfg
 
         # Avoid having to write out os+kernel for all the platforms where
         # they don't differ.
-        os_or_kernel = target.kernel if target.kernel == 'Linux' and target.os != 'Android' else target.os
+        os_or_kernel = host_or_target.kernel if host_or_target.kernel == 'Linux' and host_or_target.os != 'Android' else host_or_target.os
         rustc_target = {
             # DragonFly
             ('x86_64', 'DragonFly'): 'x86_64-unknown-dragonfly',
             # FreeBSD
             ('x86', 'FreeBSD'): 'i686-unknown-freebsd',
             ('x86_64', 'FreeBSD'): 'x86_64-unknown-freebsd',
             # NetBSD
             ('x86_64', 'NetBSD'): 'x86_64-unknown-netbsd',
@@ -115,20 +122,20 @@ def rust_target(rust_compiler, rustc, ta
             # Android
             ('x86', 'Android'): 'i686-linux-android',
             ('arm', 'Android'): 'armv7-linux-androideabi',
             # Windows
             # XXX better detection of CXX needed here, to figure out whether
             # we need i686-pc-windows-gnu instead, since mingw32 builds work.
             ('x86', 'WINNT'): 'i686-pc-windows-msvc',
             ('x86_64', 'WINNT'): 'x86_64-pc-windows-msvc',
-        }.get((target.cpu, os_or_kernel), None)
+        }.get((host_or_target.cpu, os_or_kernel), None)
 
         if rustc_target is None:
-            die("Don't know how to translate {} for rustc".format(target.alias))
+            die("Don't know how to translate {} for rustc".format(host_or_target.alias))
 
         # Check to see whether our rustc has a reasonably functional stdlib
         # for our chosen target.
         target_arg = '--target=' + rustc_target
         in_fd, in_path = mkstemp(prefix='conftest', suffix='.rs')
         out_fd, out_path = mkstemp(prefix='conftest', suffix='.rlib')
         os.close(out_fd)
         try:
@@ -143,24 +150,31 @@ def rust_target(rust_compiler, rustc, ta
             cmd = [
                 rustc,
                 '--crate-type', 'staticlib',
                 target_arg,
                 '-o', out_path,
                 in_path,
             ]
             def failed():
-                die('Cannot compile for {} with {}'.format(target.alias, rustc))
+                die('Cannot compile for {} with {}'.format(host_or_target.alias, rustc))
             check_cmd_output(*cmd, onerror=failed)
             if not os.path.exists(out_path) or os.path.getsize(out_path) == 0:
                 failed()
         finally:
             os.remove(in_path)
             os.remove(out_path)
+
         # This target is usable.
         return rustc_target
 
-set_config('RUST_TARGET', rust_target)
+    return rust_target
+
+rust_target_triple = rust_triple_alias(target)
+rust_host_triple = rust_triple_alias(host)
+
+set_config('RUST_TARGET', rust_target_triple)
+set_config('RUST_HOST_TARGET', rust_host_triple)
 
 # Until we remove all the other Rust checks in old-configure.
 add_old_configure_assignment('MOZ_RUST', rust_compiler)
 add_old_configure_assignment('RUSTC', rustc)
-add_old_configure_assignment('RUST_TARGET', rust_target)
+add_old_configure_assignment('RUST_TARGET', rust_target_triple)
--- a/build/valgrind/x86_64-redhat-linux-gnu.sup
+++ b/build/valgrind/x86_64-redhat-linux-gnu.sup
@@ -203,8 +203,319 @@
 {
    Bug 1288618 comments 119 through 127 part 2
    Memcheck:Cond
    fun:__get_cpuid
    fun:cpuid
    fun:_ZN6SkOptsL4initEv
    fun:sk_once_no_arg_adaptor
 }
+
+
+###################################################
+#  For valgrind-mochitest ("tc-M-V [tier 2]") runs on taskcluster.
+#  See bug 1248365.
+#  These are specific to Ubuntu 12.04.5, 64-bit.
+###################################################
+
+
+# Not sure what this is.  Is it the well-known
+# Memcheck-being-confused-by-zlib thing?  I suspect so.
+#
+# Conditional jump or move depends on uninitialised value(s)
+#    at 0xB6154E0: inflateReset2 (in /lib/x86_64-linux-gnu/libz.so.1.2.3.4)
+#    by 0xB6155D8: inflateInit2_ (in /lib/x86_64-linux-gnu/libz.so.1.2.3.4)
+#    by 0xADDE253: png_create_read_struct_2
+#                  (in /lib/x86_64-linux-gnu/libpng12.so.0.46.0)
+#  Uninitialised value was created by a heap allocation
+#    at 0x4C2D027: malloc (coregrind/m_replacemalloc/vg_replace_malloc.c:298)
+#    by 0xADE960F: png_malloc (in /lib/x86_64-linux-gnu/libpng12.so.0.46.0)
+#    by 0xADD1B95: ??? (in /lib/x86_64-linux-gnu/libpng12.so.0.46.0)
+#    by 0xB6155B6: inflateInit2_ (in /lib/x86_64-linux-gnu/libz.so.1.2.3.4)
+#    by 0xADDE253: png_create_read_struct_2
+#                  (in /lib/x86_64-linux-gnu/libpng12.so.0.46.0)
+#    by 0x15707869: ??? (in /usr/lib/x86_64-linux-gnu/gdk-pixbuf-2.0/2.10.0/
+#                   loaders/libpixbufloader-png.so)
+{
+   Bug 1248365: mochitest-libz-1
+   Memcheck:Cond
+   fun:inflateReset2
+   fun:inflateInit2_
+   fun:png_create_read_struct_2
+}
+
+
+# I don't know what this is.
+#
+# Conditional jump or move depends on uninitialised value(s)
+#    at 0x39608257: ??? (in /usr/lib/x86_64-linux-gnu/librsvg-2.so.2.36.1)
+#    by 0x39608E96: rsvg_handle_get_pixbuf_sub (in /usr/lib/x86_64-linux-gnu/l
+#    by 0x37D00D2A: ??? (in /usr/lib/x86_64-linux-gnu/gdk-pixbuf-2.0/2.10.0/lo
+#    by 0x88FF740: gdk_pixbuf_loader_close (in /usr/lib/x86_64-linux-gnu/libgd
+#    by 0x88FBA48: ??? (in /usr/lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.so.0.26
+#    by 0x88FD290: gdk_pixbuf_new_from_stream_at_scale (in /usr/lib/x86_64-lin
+#    by 0x6EF96A7: ??? (in /usr/lib/x86_64-linux-gnu/libgtk-3.so.0.400.2)
+#    by 0x6EFC2B1: gtk_icon_info_load_icon (in /usr/lib/x86_64-linux-gnu/libgt
+#  Uninitialised value was created by a stack allocation
+#    at 0xAB786B0: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
+{
+   Bug 1248365: mochitest-librsvg-1
+   Memcheck:Cond
+   obj:/*/librsvg-2.so.2.36*
+   fun:rsvg_handle_get_pixbuf_sub
+   obj:/*/libpixbufloader-svg.so*
+   fun:gdk_pixbuf_loader_close
+}
+
+
+# There now follow some suppressions to do with libpixman.  There are two
+# variants, one for errors in the system libpixman, and one for errors in
+# our in-tree copy.  I suspect that all of these sse2 compositing reports
+# are Memcheck false positives, possibly to do with inaccurate
+# instrumentation of the function combine1() in
+# gfx/cairo/libpixman/src/pixman-sse2.c.
+#
+# Conditional jump or move depends on uninitialised value(s)
+#    at 0xAB93A10: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
+#    by 0xAB78927: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
+#    by 0xAB40B0B: pixman_image_composite32 (in /usr/lib/x86_64-linux-gnu/libp
+#    by 0x865C95C: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11000.2)
+#    by 0x865E3CB: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11000.2)
+#    by 0x865F6EA: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11000.2)
+#    by 0x865F968: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11000.2)
+#    by 0x867D7C3: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11000.2)
+#  Uninitialised value was created by a stack allocation
+#    at 0xAB786B0: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
+{
+   Bug 1248365: mochitest-libpixman-1
+   Memcheck:Cond
+   obj:/*/libpixman-1.so.0.30*
+   obj:/*/libpixman-1.so.0.30*
+   fun:pixman_image_composite32
+}
+
+
+# Conditional jump or move depends on uninitialised value(s)
+#    at 0xF9EA219: sse2_composite_over_8888_8888
+#    by 0xF9F5B5F: _moz_pixman_image_composite32
+#    by 0xF96E29E: _clip_and_composite_boxes
+#    by 0xF96F79D: _cairo_image_surface_fill
+#    by 0xF98790C: _cairo_surface_fill
+#    by 0xF96FE2E: _cairo_gstate_fill
+#    by 0xF98B3D9: _moz_cairo_fill_preserve
+#    by 0xE4CF383: mozilla::gfx::DrawTargetCairo::DrawPattern(mozilla::gfx:
+#  Uninitialised value was created by a stack allocation
+#    at 0xB8E46B0: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
+{
+   Bug 1248365: mochitest-libpixman-2
+   Memcheck:Cond
+   fun:sse2_composite_over_8888_8888
+   fun:_moz_pixman_image_composite32
+   fun:_clip_and_composite_boxes
+   fun:_cairo_image_surface_fill
+}
+
+
+# Conditional jump or move depends on uninitialised value(s)
+#    at 0xF9D56AE: sse2_combine_over_u (in /home/worker/workspace/build/applic
+#    by 0xF9D05D4: general_composite_rect (in /home/worker/workspace/build/app
+#    by 0xF9F5B5F: _moz_pixman_image_composite32 (in /home/worker/workspace/bu
+#    by 0xF96CF63: _clip_and_composite (in /home/worker/workspace/build/applic
+#    by 0xF96D656: _clip_and_composite_boxes.part.32 (in /home/worker/workspac
+#    by 0xF96E328: _clip_and_composite_boxes (in /home/worker/workspace/build/
+#    by 0xF96F79D: _cairo_image_surface_fill (in /home/worker/workspace/build/
+#    by 0xF98790C: _cairo_surface_fill (in /home/worker/workspace/build/applic
+#  Uninitialised value was created by a stack allocation
+#    at 0xF9D024D: general_composite_rect (in /home/worker/workspace/build/app
+#
+{
+   Bug 1248365: mochitest-libpixman-3
+   Memcheck:Cond
+   fun:sse2_combine_over_u
+   fun:general_composite_rect
+   fun:_moz_pixman_image_composite32
+   fun:_clip_and_composite*
+}
+
+
+# Conditional jump or move depends on uninitialised value(s)
+#    at 0xE626A5C: mozilla::image::imgFrame::Optimize() (in /home/worker/work
+#    by 0xE626C68: mozilla::image::imgFrame::UnlockImageData() (in /home/work
+#    by 0xE608E8F: mozilla::image::RawAccessFrameRef::~RawAccessFrameRef() (i
+#    by 0xE61F5E4: mozilla::image::Decoder::~Decoder() (in /home/worker/works
+#    by 0xE630E32: mozilla::image::nsIconDecoder::~nsIconDecoder() (in /home/
+#    by 0xE61A5B2: mozilla::image::Decoder::Release() (in /home/worker/worksp
+#    by 0xE61DD73: mozilla::image::NotifyDecodeCompleteWorker::~NotifyDecodeC
+#    by 0xE61DD8F: mozilla::image::NotifyDecodeCompleteWorker::~NotifyDecodeC
+#  Uninitialised value was created by a stack allocation
+#    at 0xB8E46B0: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
+{
+   Bug 1248365: mochitest-libpixman-4
+   Memcheck:Cond
+   fun:_ZN7mozilla5image8imgFrame8OptimizeEv
+   fun:_ZN7mozilla5image8imgFrame15UnlockImageDataEv
+   fun:_ZN7mozilla5image17RawAccessFrameRefD1Ev
+   fun:_ZN7mozilla5image7DecoderD1Ev
+}
+
+
+# Not sure what this.  I can't reproduce it locally despite much trying.
+# Syscall param sendmsg(msg.msg_iov[0]) points to uninitialised byte(s)
+#    at 0x4E4533D: ??? (syscall-template.S:82)
+#    by 0xE12C0A7: IPC::Channel::ChannelImpl::ProcessOutgoingMessages() (in /h
+#    by 0xE142FD0: RunnableMethod<IPC::Channel, bool (IPC::Channel::*)(IPC::Me
+#    by 0xE1240EA: MessageLoop::RunTask(Task*) (in /home/worker/workspace/buil
+#    by 0xE128A46: MessageLoop::DeferOrRunPendingTask(MessageLoop::PendingTask
+#    by 0xE128B6D: MessageLoop::DoWork() (in /home/worker/workspace/build/appl
+#    by 0xE12272C: base::MessagePumpLibevent::Run(base::MessagePump::Delegate*
+#    by 0xE124155: MessageLoop::Run() (in /home/worker/workspace/build/applica
+{
+   Bug 1248365: mochitest-sendmsg-1
+   Memcheck:Param
+   sendmsg(msg.msg_iov[0])
+   obj:/lib/x86_64-linux-gnu/libpthread-2.15.so
+   fun:_ZN3IPC7Channel11ChannelImpl23ProcessOutgoingMessagesEv
+   fun:_ZN14RunnableMethodIN3IPC7ChannelEMS1_FbPNS0_7MessageEEN7mozilla5Tuple*
+}
+
+
+# I can't repro this either.
+# Conditional jump or move depends on uninitialised value(s)
+#    at 0x418E7E7C: ??? (in /usr/lib/x86_64-linux-gnu/libavcodec.so.53.35.0)
+#    by 0x4192D620: ??? (in /usr/lib/x86_64-linux-gnu/libavcodec.so.53.35.0)
+#    by 0x4192E717: ??? (in /usr/lib/x86_64-linux-gnu/libavcodec.so.53.35.0)
+#    by 0x41711BC4: ??? (in /usr/lib/x86_64-linux-gnu/libavcodec.so.53.35.0)
+#    by 0x41B08B6A: avcodec_open2 (in /usr/lib/x86_64-linux-gnu/libavcodec.so.
+#    by 0xEEAD89C: mozilla::FFmpegDataDecoder<53>::InitDecoder() (in /home/wor
+#    by 0xEEAE42B: mozilla::FFmpegVideoDecoder<53>::Init() (in /home/worker/wo
+#    by 0xEEA4C07: mozilla::H264Converter::Init() (in /home/worker/workspace/b
+#  Uninitialised value was created by a heap allocation
+#    at 0x4C2D11F: realloc (vg_replace_malloc.c:785)
+#    by 0x406196: moz_xrealloc (in /home/worker/workspace/build/application/fi
+#    by 0xDEB43AC: nsTArrayInfallibleAllocator::ResultTypeProxy nsTArray_base<
+#    by 0xEEAD850: mozilla::FFmpegDataDecoder<53>::InitDecoder() (in /home/wor
+#    by 0xEEAE42B: mozilla::FFmpegVideoDecoder<53>::Init() (in /home/worker/wo
+{
+   Bug 1248365: mochitest-libavcodec-1-c
+   Memcheck:Cond
+   obj:/*/libavcodec.so.53*
+   obj:/*/libavcodec.so.53*
+   obj:/*/libavcodec.so.53*
+   obj:/*/libavcodec.so.53*
+}
+{
+   Bug 1248365: mochitest-libavcodec-1-v8
+   Memcheck:Value8
+   obj:/*/libavcodec.so.53*
+   obj:/*/libavcodec.so.53*
+   obj:/*/libavcodec.so.53*
+   obj:/*/libavcodec.so.53*
+}
+
+
+# Not sure what this is, but I am inclined to think it is also probably a
+# SSE2-induced false positive similar to mochitest-libpixman-2 above.
+# Use of uninitialised value of size 8
+#    at 0xE4F3E89: FastConvertYUVToRGB32Row (in /home/worker/workspace/build/a
+#    by 0xE4F4A6D: mozilla::gfx::ConvertYCbCrToRGB32(unsigned char const*, uns
+#    by 0xE4F4B17: mozilla::gfx::ConvertYCbCrToRGB(mozilla::layers::PlanarYCbC
+#    by 0xE5227CB: mozilla::layers::PlanarYCbCrImage::GetAsSourceSurface() (in
+#    by 0xE5B2465: mozilla::layers::SharedPlanarYCbCrImage::GetAsSourceSurface
+#    by 0xE52FE44: mozilla::layers::BasicImageLayer::Paint(mozilla::gfx::DrawT
+#    by 0xE5618A1: mozilla::layers::BasicLayerManager::PaintSelfOrChildren(moz
+#    by 0xE560F83: mozilla::layers::BasicLayerManager::PaintLayer(gfxContext*,
+#  Uninitialised value was created by a stack allocation
+#    at 0x434B36B2: ??? (in /usr/lib/x86_64-linux-gnu/libavcodec.so.53.35.0)
+{
+   Bug 1248365: FastConvertYUVToRGB32Row-1
+   Memcheck:Value8
+   fun:FastConvertYUVToRGB32Row
+   fun:_ZN7mozilla3gfx19ConvertYCbCrToRGB32*
+   fun:_ZN7mozilla3gfx17ConvertYCbCrToRGB*
+   fun:_ZN7mozilla6layers16PlanarYCbCrImage18GetAsSourceSurface*
+}
+
+
+# This is probably a V false positive, due to an insufficiently accurate
+# description of the ioctl(SIOCETHTOOL) behavior.
+# Syscall param ioctl(SIOCETHTOOL) points to uninitialised byte(s)
+#    at 0x5D5CBF7: ioctl (syscall-template.S:82)
+#    by 0xF58EB67: nr_stun_get_addrs (in /home/worker/workspace/build/applica
+#    by 0xF594791: nr_stun_find_local_addresses (in /home/worker/workspace/bu
+#    by 0xF58A237: nr_ice_get_local_addresses (in /home/worker/workspace/buil
+#    by 0xF58ADDE: nr_ice_gather (in /home/worker/workspace/build/application
+#    by 0xE43F35F: mozilla::NrIceCtx::StartGathering() (in /home/worker/works
+#    by 0xE419560: mozilla::PeerConnectionMedia::EnsureIceGathering_s() (in /
+#    by 0xE41A11C: mozilla::runnable_args_memfn<RefPtr<mozilla::PeerConnectio
+#  Address 0x1cc3fb48 is on thread 6's stack
+#  in frame #1, created by nr_stun_get_addrs (???:)
+{
+   Bug 1248365: mochitest-ioctl(SIOCETHTOOL)-1
+   Memcheck:Param
+   ioctl(SIOCETHTOOL)
+   fun:ioctl
+   fun:nr_stun_get_addrs
+   fun:nr_stun_find_local_addresses
+}
+
+
+# This looks like uninitialised padding bytes in a structure owned
+# by libfontconfig.  So there's nothing we can do about it.
+# Syscall param write(buf) points to uninitialised byte(s)
+#    at 0x4E44CCD: ??? (syscall-template.S:82)
+#    by 0x9F1FF56: ??? (in /usr/lib/x86_64-linux-gnu/libfontconfig.so.1.4.4)
+#    by 0x9F2679B: ??? (in /usr/lib/x86_64-linux-gnu/libfontconfig.so.1.4.4)
+#    by 0x9F22B98: ??? (in /usr/lib/x86_64-linux-gnu/libfontconfig.so.1.4.4)
+#    by 0x9F22C5F: FcConfigAppFontAddDir (in /usr/lib/x86_64-linux-gnu/libfon
+#    by 0xE850173: gfxFcPlatformFontList::ActivateBundledFonts() (in /home/wo
+#    by 0xE852258: gfxFcPlatformFontList::InitFontListForPlatform() (in /home
+#    by 0xE895E21: gfxPlatformFontList::InitFontList() (in /home/worker/works
+#  Address 0x2316663c is 156 bytes inside a block of size 1,448 alloc'd
+#    at 0x4C2CF71: malloc (vg_replace_malloc.c:299)
+#    by 0x9F1FD1D: ??? (in /usr/lib/x86_64-linux-gnu/libfontconfig.so.1.4.4)
+#    by 0x9F26788: ??? (in /usr/lib/x86_64-linux-gnu/libfontconfig.so.1.4.4)
+#    by 0x9F22B98: ??? (in /usr/lib/x86_64-linux-gnu/libfontconfig.so.1.4.4)
+#    by 0x9F22C5F: FcConfigAppFontAddDir (in /usr/lib/x86_64-linux-gnu/libfon
+#    by 0xE850173: gfxFcPlatformFontList::ActivateBundledFonts() (in /home/wo
+#    by 0xE852258: gfxFcPlatformFontList::InitFontListForPlatform() (in /home
+#    by 0xE895E21: gfxPlatformFontList::InitFontList() (in /home/worker/works
+{
+   Bug 1248365: libfontconfig-1
+   Memcheck:Param
+   write(buf)
+   obj:/*/libpthread*.so*
+   obj:/*/libfontconfig.so*
+   ...
+   obj:/*/libfontconfig.so*
+   fun:FcConfigAppFontAddDir
+}
+
+
+# There's nothing we can do about this short of throwing in
+# --show-mismatched-frees=no, but that's a bit drastic, so for now,
+# just suppress it.
+#
+# Mismatched free() / delete / delete []
+#    at 0x4C2BE97: free (vg_replace_malloc.c:530)
+#    by 0xFCD09EC: ots::ots_post_free(ots::Font*) (in /home/worker/workspace/
+#    by 0xFCC600E: ots::Font::~Font() (in /home/worker/workspace/build/applic
+#    by 0xFCCBFA5: ots::OTSContext::Process(ots::OTSStream*, unsigned char co
+#    by 0xE7D7C8D: gfxUserFontEntry::SanitizeOpenTypeData(unsigned char const
+#    by 0xE7E371D: gfxUserFontEntry::LoadPlatformFont(unsigned char const*, u
+#    by 0xE7E48AA: gfxUserFontEntry::FontDataDownloadComplete(unsigned char c
+#    by 0xF49D25B: nsFontFaceLoader::OnStreamComplete(nsIStreamLoader*, nsISu
+#  Address 0x15671f00 is 0 bytes inside a block of size 490 alloc'd
+#    at 0x4C2CAEE: operator new(unsigned long) (vg_replace_malloc.c:332)
+#    by 0xF6AB737: std::vector<unsigned short, std::allocator<unsigned short>
+#    by 0xFCD0FDE: ots::ots_post_parse(ots::Font*, unsigned char const*, unsi
+#    by 0xFCCA3D9: (anonymous namespace)::ProcessGeneric(ots::OpenTypeFile*, 
+#    by 0xFCCB17E: (anonymous namespace)::ProcessTTF(ots::OpenTypeFile*, ots:
+#    by 0xFCCBA54: ots::OTSContext::Process(ots::OTSStream*, unsigned char co
+#    by 0xE7D7C8D: gfxUserFontEntry::SanitizeOpenTypeData(unsigned char const
+#    by 0xE7E371D: gfxUserFontEntry::LoadPlatformFont(unsigned char const*, u
+{
+   Bug 1248365: ots::Font::~Font()-1
+   Memcheck:Free
+   fun:free
+   fun:_ZN3ots13ots_post_free*
+   fun:_ZN3ots4FontD1Ev
+   fun:_ZN3ots10OTSContext7Process*
+}
--- a/config/makefiles/target_binaries.mk
+++ b/config/makefiles/target_binaries.mk
@@ -3,17 +3,17 @@
 #
 # 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/.
 
 ifndef NO_DIST_INSTALL
 
 ifneq (,$(strip $(PROGRAM)$(SIMPLE_PROGRAMS)))
-PROGRAMS_EXECUTABLES = $(SIMPLE_PROGRAMS) $(PROGRAM)
+PROGRAMS_EXECUTABLES = $(SIMPLE_PROGRAMS) $(PROGRAM) $(RUST_PROGRAMS)
 PROGRAMS_DEST ?= $(FINAL_TARGET)
 PROGRAMS_TARGET := target
 INSTALL_TARGETS += PROGRAMS
 endif
 
 ifdef LIBRARY
 ifdef DIST_INSTALL
 ifdef IS_COMPONENT
@@ -26,17 +26,17 @@ endif # LIBRARY
 ifdef SHARED_LIBRARY
 SHARED_LIBRARY_FILES = $(SHARED_LIBRARY)
 SHARED_LIBRARY_DEST ?= $(FINAL_TARGET)$(if $(IS_COMPONENT),/components)
 SHARED_LIBRARY_TARGET = target
 INSTALL_TARGETS += SHARED_LIBRARY
 endif # SHARED_LIBRARY
 
 ifneq (,$(strip $(HOST_SIMPLE_PROGRAMS)$(HOST_PROGRAM)))
-HOST_PROGRAMS_EXECUTABLES = $(HOST_SIMPLE_PROGRAMS) $(HOST_PROGRAM)
+HOST_PROGRAMS_EXECUTABLES = $(HOST_SIMPLE_PROGRAMS) $(HOST_PROGRAM) $(HOST_RUST_PROGRAMS)
 HOST_PROGRAMS_DEST ?= $(DIST)/host/bin
 HOST_PROGRAMS_TARGET = host
 INSTALL_TARGETS += HOST_PROGRAMS
 endif
 
 endif # !NO_DIST_INSTALL
 
 # EOF
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -542,19 +542,19 @@ STATIC_LIBS_DEPS := $(foreach l,$(STATIC
 GLOBAL_DEPS += Makefile $(addprefix $(DEPTH)/config/,$(INCLUDED_AUTOCONF_MK)) $(MOZILLA_DIR)/config/config.mk
 
 ##############################################
 ifdef COMPILE_ENVIRONMENT
 OBJ_TARGETS = $(OBJS) $(PROGOBJS) $(HOST_OBJS) $(HOST_PROGOBJS)
 
 compile:: host target
 
-host:: $(HOST_LIBRARY) $(HOST_PROGRAM) $(HOST_SIMPLE_PROGRAMS)
+host:: $(HOST_LIBRARY) $(HOST_PROGRAM) $(HOST_SIMPLE_PROGRAMS) $(HOST_RUST_PROGRAMS)
 
-target:: $(LIBRARY) $(SHARED_LIBRARY) $(PROGRAM) $(SIMPLE_PROGRAMS) $(RUST_LIBRARY_FILE)
+target:: $(LIBRARY) $(SHARED_LIBRARY) $(PROGRAM) $(SIMPLE_PROGRAMS) $(RUST_LIBRARY_FILE) $(RUST_PROGRAMS)
 
 include $(MOZILLA_DIR)/config/makefiles/target_binaries.mk
 endif
 
 ##############################################
 ifneq (1,$(NO_PROFILE_GUIDED_OPTIMIZE))
 ifdef MOZ_PROFILE_USE
 ifeq ($(OS_ARCH)_$(GNU_CC), WINNT_)
@@ -901,29 +901,29 @@ ifdef ASFILES
 # The AS_DASH_C_FLAG is needed cause not all assemblers (Solaris) accept
 # a '-c' flag.
 $(ASOBJS):
 	$(REPORT_BUILD_VERBOSE)
 	$(AS) $(ASOUTOPTION)$@ $(ASFLAGS) $($(notdir $<)_FLAGS) $(AS_DASH_C_FLAG) $(_VPATH_SRCS)
 endif
 
 ifdef MOZ_RUST
-ifdef RUST_LIBRARY_FILE
+cargo_host_flag := --target=$(RUST_HOST_TARGET)
+cargo_target_flag := --target=$(RUST_TARGET)
 
 # Permit users to pass flags to cargo from their mozconfigs (e.g. --color=always).
 cargo_build_flags = $(CARGOFLAGS)
 ifndef MOZ_DEBUG
 cargo_build_flags = --release
 endif
 ifdef MOZ_CARGO_SUPPORTS_FROZEN
 cargo_build_flags += --frozen
 endif
 
 cargo_build_flags += --manifest-path $(CARGO_FILE)
-cargo_build_flags += --target=$(RUST_TARGET)
 cargo_build_flags += --verbose
 
 # Enable color output if original stdout was a TTY and color settings
 # aren't already present. This essentially restores the default behavior
 # of cargo when running via `mach`.
 ifdef MACH_STDOUT_ISATTY
 ifeq (,$(findstring --color,$(cargo_build_flags)))
 cargo_build_flags += --color=always
@@ -937,27 +937,44 @@ endif
 # choices, and Cargo only supports two, we choose to enable various
 # optimization levels in our Cargo.toml files all the time, and override the
 # optimization level here, if necessary.  (The Cargo.toml files already
 # specify debug-assertions appropriately for --{disable,enable}-debug.)
 ifndef MOZ_OPTIMIZE
 rustflags_override = RUSTFLAGS='-C opt-level=0'
 endif
 
+ifdef RUST_LIBRARY_FILE
+
 # Assume any system libraries rustc links against are already in the target's LIBS.
 #
 # We need to run cargo unconditionally, because cargo is the only thing that
 # has full visibility into how changes in Rust sources might affect the final
 # build.
-force-cargo-build:
+force-cargo-library-build:
+	$(REPORT_BUILD)
+	env $(rustflags_override) CARGO_TARGET_DIR=. RUSTC=$(RUSTC) $(CARGO) build --lib $(cargo_build_flags) $(cargo_target_flag) --
+
+$(RUST_LIBRARY_FILE): force-cargo-library-build
+endif # RUST_LIBRARY_FILE
+
+ifdef RUST_PROGRAMS
+force-cargo-program-build:
 	$(REPORT_BUILD)
-	env $(rustflags_override) CARGO_TARGET_DIR=. RUSTC=$(RUSTC) $(CARGO) build $(cargo_build_flags) --
+	env $(rustflags_override) CARGO_TARGET_DIR=. RUSTC=$(RUSTC) $(CARGO) build $(addprefix --bin ,$(RUST_CARGO_PROGRAMS)) $(cargo_build_flags) $(cargo_target_flag) --
 
-$(RUST_LIBRARY_FILE): force-cargo-build
-endif # CARGO_FILE
+$(RUST_PROGRAMS): force-cargo-program-build
+endif # RUST_PROGRAMS
+ifdef HOST_RUST_PROGRAMS
+force-cargo-host-program-build:
+	$(REPORT_BUILD)
+	env $(rustflags_override) CARGO_TARGET_DIR=. RUSTC=$(RUSTC) $(CARGO) build $(addprefix --bin ,$(HOST_RUST_CARGO_PROGRAMS)) $(cargo_build_flags) $(cargo_host_flag) --
+
+$(HOST_RUST_PROGRAMS): force-cargo-host-program-build
+endif # HOST_RUST_PROGRAMS
 endif # MOZ_RUST
 
 $(SOBJS):
 	$(REPORT_BUILD)
 	$(AS) -o $@ $(DEFINES) $(ASFLAGS) $($(notdir $<)_FLAGS) $(LOCAL_INCLUDES) -c $<
 
 $(CPPOBJS):
 	$(REPORT_BUILD_VERBOSE)
--- a/devtools/client/inspector/computed/computed.js
+++ b/devtools/client/inspector/computed/computed.js
@@ -12,17 +12,16 @@ const {ELEMENT_STYLE} = require("devtool
 const promise = require("promise");
 const defer = require("devtools/shared/defer");
 const Services = require("Services");
 const {OutputParser} = require("devtools/client/shared/output-parser");
 const {PrefObserver, PREF_ORIG_SOURCES} = require("devtools/client/styleeditor/utils");
 const {createChild} = require("devtools/client/inspector/shared/utils");
 const {gDevTools} = require("devtools/client/framework/devtools");
 const {getCssProperties} = require("devtools/shared/fronts/css-properties");
-const HighlightersOverlay = require("devtools/client/inspector/shared/highlighters-overlay");
 const {
   VIEW_NODE_SELECTOR_TYPE,
   VIEW_NODE_PROPERTY_TYPE,
   VIEW_NODE_VALUE_TYPE,
   VIEW_NODE_IMAGE_URL_TYPE,
 } = require("devtools/client/inspector/shared/node-types");
 const StyleInspectorMenu = require("devtools/client/inspector/shared/style-inspector-menu");
 const TooltipsOverlay = require("devtools/client/inspector/shared/tooltips-overlay");
@@ -147,16 +146,17 @@ UpdateProcess.prototype = {
  * @param {Document} document
  *        The document that will contain the computed view.
  * @param {PageStyleFront} pageStyle
  *        Front for the page style actor that will be providing
  *        the style information.
  */
 function CssComputedView(inspector, document, pageStyle) {
   this.inspector = inspector;
+  this.highlighters = inspector.highlighters;
   this.styleDocument = document;
   this.styleWindow = this.styleDocument.defaultView;
   this.pageStyle = pageStyle;
 
   this.propertyViews = [];
 
   let cssProperties = getCssProperties(inspector.toolbox);
   this._outputParser = new OutputParser(document, cssProperties);
@@ -211,18 +211,17 @@ function CssComputedView(inspector, docu
   this.createStyleViews();
 
   this._contextmenu = new StyleInspectorMenu(this, { isRuleView: false });
 
   // Add the tooltips and highlightersoverlay
   this.tooltips = new TooltipsOverlay(this);
   this.tooltips.addToView();
 
-  this.highlighters = new HighlightersOverlay(this);
-  this.highlighters.addToView();
+  this.highlighters.addToView(this);
 }
 
 /**
  * Lookup a l10n string in the shared styleinspector string bundle.
  *
  * @param {String} name
  *        The key to lookup.
  * @returns {String} localized version of the given key.
@@ -748,17 +747,17 @@ CssComputedView.prototype = {
 
     // Remove context menu
     if (this._contextmenu) {
       this._contextmenu.destroy();
       this._contextmenu = null;
     }
 
     this.tooltips.destroy();
-    this.highlighters.destroy();
+    this.highlighters.removeFromView(this);
 
     // Remove bound listeners
     this.styleDocument.removeEventListener("mousedown", this.focusWindow);
     this.element.removeEventListener("click", this._onClick);
     this.element.removeEventListener("copy", this._onCopy);
     this.element.removeEventListener("contextmenu", this._onContextMenu);
     this.searchField.removeEventListener("input", this._onFilterStyles);
     this.searchField.removeEventListener("contextmenu",
@@ -776,16 +775,17 @@ CssComputedView.prototype = {
 
     // Property views
     for (let propView of this.propertyViews) {
       propView.destroy();
     }
     this.propertyViews = null;
 
     this.inspector = null;
+    this.highlighters = null;
     this.styleDocument = null;
     this.styleWindow = null;
 
     this._isDestroyed = true;
   }
 };
 
 function PropertyInfo(tree, name) {
--- a/devtools/client/inspector/inspector.js
+++ b/devtools/client/inspector/inspector.js
@@ -19,24 +19,25 @@ var {KeyShortcuts} = require("devtools/c
 var {Task} = require("devtools/shared/task");
 const {initCssProperties} = require("devtools/shared/fronts/css-properties");
 const nodeConstants = require("devtools/shared/dom-node-constants");
 const Telemetry = require("devtools/client/shared/telemetry");
 
 const Menu = require("devtools/client/framework/menu");
 const MenuItem = require("devtools/client/framework/menu-item");
 
-const {CommandUtils} = require("devtools/client/shared/developer-toolbar");
+const {HTMLBreadcrumbs} = require("devtools/client/inspector/breadcrumbs");
 const {ComputedViewTool} = require("devtools/client/inspector/computed/computed");
 const {FontInspector} = require("devtools/client/inspector/fonts/fonts");
-const {HTMLBreadcrumbs} = require("devtools/client/inspector/breadcrumbs");
 const {InspectorSearch} = require("devtools/client/inspector/inspector-search");
+const {RuleViewTool} = require("devtools/client/inspector/rules/rules");
+const HighlightersOverlay = require("devtools/client/inspector/shared/highlighters-overlay");
+const {ToolSidebar} = require("devtools/client/inspector/toolsidebar");
 const MarkupView = require("devtools/client/inspector/markup/markup");
-const {RuleViewTool} = require("devtools/client/inspector/rules/rules");
-const {ToolSidebar} = require("devtools/client/inspector/toolsidebar");
+const {CommandUtils} = require("devtools/client/shared/developer-toolbar");
 const {ViewHelpers} = require("devtools/client/shared/widgets/view-helpers");
 const clipboardHelper = require("devtools/shared/platform/clipboard");
 
 const {LocalizationHelper, localizeMarkup} = require("devtools/shared/l10n");
 const INSPECTOR_L10N =
       new LocalizationHelper("devtools/client/locales/inspector.properties");
 const TOOLBOX_L10N = new LocalizationHelper("devtools/client/locales/toolbox.properties");
 
@@ -87,16 +88,17 @@ const PORTRAIT_MODE_WIDTH = 700;
  */
 function Inspector(toolbox) {
   this._toolbox = toolbox;
   this._target = toolbox.target;
   this.panelDoc = window.document;
   this.panelWin = window;
   this.panelWin.inspector = this;
 
+  this.highlighters = new HighlightersOverlay(this);
   this.telemetry = new Telemetry();
 
   this.nodeMenuTriggerInfo = null;
 
   this._handleRejectionIfNotDestroyed = this._handleRejectionIfNotDestroyed.bind(this);
   this._onBeforeNavigate = this._onBeforeNavigate.bind(this);
   this.onNewRoot = this.onNewRoot.bind(this);
   this._onContextMenu = this._onContextMenu.bind(this);
@@ -906,23 +908,29 @@ Inspector.prototype = {
     this.teardownSplitter();
 
     this.sidebar = null;
 
     this.teardownToolbar();
     this.breadcrumbs.destroy();
     this.selection.off("new-node-front", this.onNewSelection);
     this.selection.off("detached-front", this.onDetached);
+
     let markupDestroyer = this._destroyMarkup();
+
     this.panelWin.inspector = null;
     this.target = null;
     this.panelDoc = null;
     this.panelWin = null;
     this.breadcrumbs = null;
     this._toolbox = null;
+
+    this.highlighters.destroy();
+    this.highlighters = null;
+
     this.search.destroy();
     this.search = null;
     this.searchBox = null;
 
     this._panelDestroyer = promise.all([
       sidebarDestroyer,
       markupDestroyer,
       cssPropertiesDestroyer
--- a/devtools/client/inspector/rules/rules.js
+++ b/devtools/client/inspector/rules/rules.js
@@ -14,17 +14,16 @@ const {l10n} = require("devtools/shared/
 const {ELEMENT_STYLE} = require("devtools/shared/specs/styles");
 const {OutputParser} = require("devtools/client/shared/output-parser");
 const {PrefObserver, PREF_ORIG_SOURCES} = require("devtools/client/styleeditor/utils");
 const {ElementStyle} = require("devtools/client/inspector/rules/models/element-style");
 const {Rule} = require("devtools/client/inspector/rules/models/rule");
 const {RuleEditor} = require("devtools/client/inspector/rules/views/rule-editor");
 const {gDevTools} = require("devtools/client/framework/devtools");
 const {getCssProperties} = require("devtools/shared/fronts/css-properties");
-const HighlightersOverlay = require("devtools/client/inspector/shared/highlighters-overlay");
 const {
   VIEW_NODE_SELECTOR_TYPE,
   VIEW_NODE_PROPERTY_TYPE,
   VIEW_NODE_VALUE_TYPE,
   VIEW_NODE_IMAGE_URL_TYPE,
   VIEW_NODE_LOCATION_TYPE,
 } = require("devtools/client/inspector/shared/node-types");
 const StyleInspectorMenu = require("devtools/client/inspector/shared/style-inspector-menu");
@@ -95,16 +94,17 @@ const FILTER_STRICT_RE = /\s*`(.*?)`\s*$
  *        The CSS rule view can use this object to store metadata
  *        that might outlast the rule view, particularly the current
  *        set of disabled properties.
  * @param {PageStyleFront} pageStyle
  *        The PageStyleFront for communicating with the remote server.
  */
 function CssRuleView(inspector, document, store, pageStyle) {
   this.inspector = inspector;
+  this.highlighters = inspector.highlighters;
   this.styleDocument = document;
   this.styleWindow = this.styleDocument.defaultView;
   this.store = store || {};
   this.pageStyle = pageStyle;
 
   // Allow tests to override throttling behavior, as this can cause intermittents.
   this.throttle = throttle;
 
@@ -172,18 +172,18 @@ function CssRuleView(inspector, document
 
   this._showEmpty();
 
   this._contextmenu = new StyleInspectorMenu(this, { isRuleView: true });
 
   // Add the tooltips and highlighters to the view
   this.tooltips = new TooltipsOverlay(this);
   this.tooltips.addToView();
-  this.highlighters = new HighlightersOverlay(this);
-  this.highlighters.addToView();
+
+  this.highlighters.addToView(this);
 
   EventEmitter.decorate(this);
 }
 
 CssRuleView.prototype = {
   // The element that we're inspecting.
   _viewedElement: null,
 
@@ -247,59 +247,47 @@ CssRuleView.prototype = {
    *
    * @param {DOMNode} selectorIcon
    *        The icon that was clicked to toggle the selector. The
    *        class 'highlighted' will be added when the selector is
    *        highlighted.
    * @param {String} selector
    *        The selector used to find nodes in the page.
    */
-  toggleSelectorHighlighter: function (selectorIcon, selector) {
+  toggleSelectorHighlighter: Task.async(function* (selectorIcon, selector) {
     if (this.lastSelectorIcon) {
       this.lastSelectorIcon.classList.remove("highlighted");
     }
     selectorIcon.classList.remove("highlighted");
 
-    this.unhighlightSelector().then(() => {
-      if (selector !== this.highlighters.selectorHighlighterShown) {
-        this.highlighters.selectorHighlighterShown = selector;
-        selectorIcon.classList.add("highlighted");
-        this.lastSelectorIcon = selectorIcon;
-        this.highlightSelector(selector).then(() => {
-          this.emit("ruleview-selectorhighlighter-toggled", true);
-        }, e => console.error(e));
-      } else {
-        this.highlighters.selectorHighlighterShown = null;
-        this.emit("ruleview-selectorhighlighter-toggled", false);
-      }
-    }, e => console.error(e));
-  },
-
-  highlightSelector: Task.async(function* (selector) {
-    let highlighter = yield this.getSelectorHighlighter();
-    if (!highlighter) {
-      return;
-    }
-
-    let node = this.inspector.selection.nodeFront;
-
-    yield highlighter.show(node, {
-      hideInfoBar: true,
-      hideGuides: true,
-      selector
-    });
-  }),
-
-  unhighlightSelector: Task.async(function* () {
     let highlighter = yield this.getSelectorHighlighter();
     if (!highlighter) {
       return;
     }
 
     yield highlighter.hide();
+
+    if (selector !== this.highlighters.selectorHighlighterShown) {
+      this.highlighters.selectorHighlighterShown = selector;
+      selectorIcon.classList.add("highlighted");
+      this.lastSelectorIcon = selectorIcon;
+
+      let node = this.inspector.selection.nodeFront;
+
+      yield highlighter.show(node, {
+        hideInfoBar: true,
+        hideGuides: true,
+        selector
+      });
+
+      this.emit("ruleview-selectorhighlighter-toggled", true);
+    } else {
+      this.highlighters.selectorHighlighterShown = null;
+      this.emit("ruleview-selectorhighlighter-toggled", false);
+    }
   }),
 
   /**
    * Get the type of a given node in the rule-view
    *
    * @param {DOMNode} node
    *        The node which we want information about
    * @return {Object} The type information object contains the following props:
@@ -678,17 +666,17 @@ CssRuleView.prototype = {
 
     // Remove context menu
     if (this._contextmenu) {
       this._contextmenu.destroy();
       this._contextmenu = null;
     }
 
     this.tooltips.destroy();
-    this.highlighters.destroy();
+    this.highlighters.removeFromView(this);
 
     // Remove bound listeners
     this.shortcuts.destroy();
     this.element.removeEventListener("copy", this._onCopy);
     this.element.removeEventListener("contextmenu", this._onContextMenu);
     this.addRuleButton.removeEventListener("click", this._onAddRule);
     this.searchField.removeEventListener("input", this._onFilterStyles);
     this.searchField.removeEventListener("contextmenu",
@@ -704,16 +692,17 @@ CssRuleView.prototype = {
     this.searchClearButton = null;
     this.pseudoClassPanel = null;
     this.pseudoClassToggle = null;
     this.hoverCheckbox = null;
     this.activeCheckbox = null;
     this.focusCheckbox = null;
 
     this.inspector = null;
+    this.highlighters = null;
     this.styleDocument = null;
     this.styleWindow = null;
 
     if (this.element.parentNode) {
       this.element.parentNode.removeChild(this.element);
     }
 
     if (this._elementStyle) {
--- a/devtools/client/inspector/shared/highlighters-overlay.js
+++ b/devtools/client/inspector/shared/highlighters-overlay.js
@@ -11,121 +11,119 @@
  * property values.
  */
 
 const promise = require("promise");
 const EventEmitter = require("devtools/shared/event-emitter");
 const { VIEW_NODE_VALUE_TYPE } = require("devtools/client/inspector/shared/node-types");
 
 /**
- * Manages all highlighters in the style-inspector.
+ * Highlighters overlay is a singleton managing all highlighters in the Inspector.
  *
- * @param  {CssRuleView|CssComputedView} view
- *         Either the rule-view or computed-view panel
+ * @param  {Inspector} inspector
+ *         Inspector toolbox panel.
  */
-function HighlightersOverlay(view) {
-  this.view = view;
+function HighlightersOverlay(inspector) {
+  this.inspector = inspector;
+  this.highlighters = {};
+  this.highlighterUtils = this.inspector.toolbox.highlighterUtils;
 
-  let {CssRuleView} = require("devtools/client/inspector/rules/rules");
-  this.isRuleView = view instanceof CssRuleView;
-
-  this.highlighters = {};
+  // Only initialize the overlay if at least one of the highlighter types is supported.
+  this.supportsHighlighters = this.highlighterUtils.supportsCustomHighlighters();
 
   // NodeFront of the grid container that is highlighted.
   this.gridHighlighterShown = null;
   // Name of the highlighter shown on mouse hover.
   this.hoveredHighlighterShown = null;
   // Name of the selector highlighter shown.
   this.selectorHighlighterShown = null;
 
-  this.highlighterUtils = this.view.inspector.toolbox.highlighterUtils;
-
-  // Only initialize the overlay if at least one of the highlighter types is
-  // supported.
-  this.supportsHighlighters =
-    this.highlighterUtils.supportsCustomHighlighters();
-
   this._onClick = this._onClick.bind(this);
   this._onMouseMove = this._onMouseMove.bind(this);
   this._onMouseOut = this._onMouseOut.bind(this);
   this._onWillNavigate = this._onWillNavigate.bind(this);
 
   EventEmitter.decorate(this);
 }
 
 HighlightersOverlay.prototype = {
+  get isRuleView() {
+    return this.inspector.sidebar.getCurrentTabID() == "ruleview";
+  },
+
   /**
-   * Add the highlighters overlay to the view. This will start tracking mouse
-   * movements and display highlighters when needed.
+   * Add the highlighters overlay to the view. This will start tracking mouse events
+   * and display highlighters when needed.
+   *
+   * @param  {CssRuleView|CssComputedView|LayoutView} view
+   *         Either the rule-view or computed-view panel to add the highlighters overlay.
+   *
    */
-  addToView: function () {
-    if (!this.supportsHighlighters || this._isStarted || this._isDestroyed) {
+  addToView: function (view) {
+    if (!this.supportsHighlighters) {
       return;
     }
 
-    let el = this.view.element;
+    let el = view.element;
     el.addEventListener("click", this._onClick, true);
     el.addEventListener("mousemove", this._onMouseMove, false);
     el.addEventListener("mouseout", this._onMouseOut, false);
     el.ownerDocument.defaultView.addEventListener("mouseout", this._onMouseOut, false);
 
-    if (this.isRuleView) {
-      this.view.inspector.target.on("will-navigate", this._onWillNavigate);
-    }
-
-    this._isStarted = true;
+    this.inspector.target.on("will-navigate", this._onWillNavigate);
   },
 
   /**
-   * Remove the overlay from the current view. This will stop tracking mouse
-   * movement and showing highlighters.
+   * Remove the overlay from the given view. This will stop tracking mouse movement and
+   * showing highlighters.
+   *
+   * @param  {CssRuleView|CssComputedView|LayoutView} view
+   *         Either the rule-view or computed-view panel to remove the highlighters
+   *         overlay.
    */
-  removeFromView: function () {
-    if (!this.supportsHighlighters || !this._isStarted || this._isDestroyed) {
+  removeFromView: function (view) {
+    if (!this.supportsHighlighters) {
       return;
     }
 
-    let el = this.view.element;
+    let el = view.element;
     el.removeEventListener("click", this._onClick, true);
     el.removeEventListener("mousemove", this._onMouseMove, false);
     el.removeEventListener("mouseout", this._onMouseOut, false);
 
-    if (this.isRuleView) {
-      this.view.inspector.target.off("will-navigate", this._onWillNavigate);
-    }
-
-    this._isStarted = false;
+    this.inspector.target.off("will-navigate", this._onWillNavigate);
   },
 
   _onClick: function (event) {
     // Bail out if the target is not a grid property value.
-    if (!this._isDisplayGridValue(event.target)) {
+    if (!this._isRuleViewDisplayGrid(event.target)) {
       return;
     }
 
     event.stopPropagation();
 
     this._getHighlighter("CssGridHighlighter").then(highlighter => {
-      let node = this.view.inspector.selection.nodeFront;
+      let node = this.inspector.selection.nodeFront;
 
       // Toggle off the grid highlighter if the grid highlighter toggle is clicked
       // for the current highlighted grid.
       if (node === this.gridHighlighterShown) {
         return highlighter.hide();
       }
 
       return highlighter.show(node);
     }).then(isGridShown => {
       // Toggle all the grid icons in the current rule view.
-      for (let gridIcon of this.view.element.querySelectorAll(".ruleview-grid")) {
+      let ruleViewEl = this.inspector.ruleview.view.element;
+      for (let gridIcon of ruleViewEl.querySelectorAll(".ruleview-grid")) {
         gridIcon.classList.toggle("active", isGridShown);
       }
 
       if (isGridShown) {
-        this.gridHighlighterShown = this.view.inspector.selection.nodeFront;
+        this.gridHighlighterShown = this.inspector.selection.nodeFront;
         this.emit("highlighter-shown");
       } else {
         this.gridHighlighterShown = null;
         this.emit("highlighter-hidden");
       }
     }).catch(e => console.error(e));
   },
 
@@ -135,31 +133,33 @@ HighlightersOverlay.prototype = {
       return;
     }
 
     // Only one highlighter can be displayed at a time, hide the currently shown.
     this._hideHoveredHighlighter();
 
     this._lastHovered = event.target;
 
-    let nodeInfo = this.view.getNodeInfo(event.target);
+    let view = this.isRuleView ?
+      this.inspector.ruleview.view : this.inspector.computedview.computedView;
+    let nodeInfo = view.getNodeInfo(event.target);
     if (!nodeInfo) {
       return;
     }
 
     // Choose the type of highlighter required for the hovered node.
     let type;
     if (this._isRuleViewTransform(nodeInfo) ||
         this._isComputedViewTransform(nodeInfo)) {
       type = "CssTransformHighlighter";
     }
 
     if (type) {
       this.hoveredHighlighterShown = type;
-      let node = this.view.inspector.selection.nodeFront;
+      let node = this.inspector.selection.nodeFront;
       this._getHighlighter(type)
           .then(highlighter => highlighter.show(node))
           .then(shown => {
             if (shown) {
               this.emit("highlighter-shown");
             }
           });
     }
@@ -216,17 +216,17 @@ HighlightersOverlay.prototype = {
 
   /**
    * Is the current clicked node a grid display property value in the
    * rule-view.
    *
    * @param  {DOMNode} node
    * @return {Boolean}
    */
-  _isDisplayGridValue: function (node) {
+  _isRuleViewDisplayGrid: function (node) {
     return this.isRuleView && node.classList.contains("ruleview-grid");
   },
 
   /**
    * Hide the currently shown grid highlighter.
    */
   _hideGridHighlighter: function () {
     if (!this.gridHighlighterShown || !this.highlighters.CssGridHighlighter) {
@@ -284,32 +284,26 @@ HighlightersOverlay.prototype = {
     });
   },
 
   /**
    * Destroy this overlay instance, removing it from the view and destroying
    * all initialized highlighters.
    */
   destroy: function () {
-    this.removeFromView();
-
     for (let type in this.highlighters) {
       if (this.highlighters[type]) {
         this.highlighters[type].finalize();
         this.highlighters[type] = null;
       }
     }
 
+    this.inspector = null;
     this.highlighters = null;
-
+    this.highlighterUtils = null;
+    this.supportsHighlighters = null;
     this.gridHighlighterShown = null;
     this.hoveredHighlighterShown = null;
     this.selectorHighlighterShown = null;
-
-    this.highlighterUtils = null;
-    this.isRuleView = null;
-    this.view = null;
-
-    this._isDestroyed = true;
   }
 };
 
 module.exports = HighlightersOverlay;
--- a/devtools/client/inspector/shared/test/browser_styleinspector_transform-highlighter-01.js
+++ b/devtools/client/inspector/shared/test/browser_styleinspector_transform-highlighter-01.js
@@ -1,15 +1,16 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-// Test that the css transform highlighter is created only when asked
+// Test that the css transform highlighter is created only when asked and only one
+// instance exists across the inspector
 
 const TEST_URI = `
   <style type="text/css">
     body {
       transform: skew(16deg);
     }
   </style>
   Test the css transform highlighter
@@ -32,17 +33,13 @@ add_task(function* () {
   is(h, h2,
     "The same instance of highlighter is returned everytime in the rule-view");
 
   let onComputedViewReady = inspector.once("computed-view-refreshed");
   let cView = selectComputedView(inspector);
   yield onComputedViewReady;
   overlay = cView.highlighters;
 
-  ok(!overlay.highlighters[TYPE], "No highlighter exists in the computed-view");
-  h = yield overlay._getHighlighter(TYPE);
-  ok(overlay.highlighters[TYPE],
-    "The highlighter has been created in the computed-view");
-  is(h, overlay.highlighters[TYPE], "The right highlighter has been created");
-  h2 = yield overlay._getHighlighter(TYPE);
-  is(h, h2, "The same instance of highlighter is returned everytime " +
+  ok(overlay.highlighters[TYPE], "The highlighter exists in the computed-view");
+  let h3 = yield overlay._getHighlighter(TYPE);
+  is(h, h3, "The same instance of highlighter is returned everytime " +
     "in the computed-view");
 });
--- a/devtools/client/inspector/shared/test/browser_styleinspector_transform-highlighter-02.js
+++ b/devtools/client/inspector/shared/test/browser_styleinspector_transform-highlighter-02.js
@@ -37,21 +37,26 @@ add_task(function* () {
   hs._onMouseMove({target: valueSpan});
   yield onHighlighterShown;
 
   let onComputedViewReady = inspector.once("computed-view-refreshed");
   let cView = selectComputedView(inspector);
   yield onComputedViewReady;
   hs = cView.highlighters;
 
-  ok(!hs.highlighters[TYPE], "No highlighter exists in the computed-view (1)");
+  info("Remove the created transform highlighter");
+  hs.highlighters[TYPE].finalize();
+  hs.highlighters[TYPE] = null;
 
   info("Faking a mousemove on a non-transform property");
   ({valueSpan} = getComputedViewProperty(cView, "color"));
   hs._onMouseMove({target: valueSpan});
-  ok(!hs.highlighters[TYPE], "No highlighter exists in the computed-view (2)");
+  ok(!hs.highlighters[TYPE], "No highlighter exists in the computed-view (3)");
 
   info("Faking a mousemove on a transform property");
   ({valueSpan} = getComputedViewProperty(cView, "transform"));
   onHighlighterShown = hs.once("highlighter-shown");
   hs._onMouseMove({target: valueSpan});
   yield onHighlighterShown;
+
+  ok(hs.highlighters[TYPE],
+    "The highlighter has been created in the computed-view");
 });
--- a/devtools/client/themes/netmonitor.css
+++ b/devtools/client/themes/netmonitor.css
@@ -47,16 +47,17 @@
   /* workaround for textbox not supporting the @crop attribute */
   text-overflow: ellipsis;
 }
 
 /* Responsive sidebar */
 @media (max-width: 700px) {
   #toolbar-spacer,
   #details-pane-toggle,
+  #details-pane.pane-collapsed,
   .requests-menu-waterfall,
   #requests-menu-network-summary-button > .summary-info-text {
     display: none;
   }
 }
 
 :root.theme-dark {
   --table-splitter-color: rgba(255,255,255,0.15);
--- a/dom/audiochannel/AudioChannelService.cpp
+++ b/dom/audiochannel/AudioChannelService.cpp
@@ -608,17 +608,17 @@ AudioChannelService::RefreshAgentsVolume
                                                    winData->mChannels[(uint32_t)aAudioChannel].mMuted);
   }
 
   RefreshAgentsVolume(aWindow);
 }
 
 void
 AudioChannelService::RefreshAgents(nsPIDOMWindowOuter* aWindow,
-                                   mozilla::function<void(AudioChannelAgent*)> aFunc)
+                                   std::function<void(AudioChannelAgent*)> aFunc)
 {
   MOZ_ASSERT(aWindow);
   MOZ_ASSERT(aWindow->IsOuterWindow());
 
   nsCOMPtr<nsPIDOMWindowOuter> topWindow = aWindow->GetScriptableTop();
   if (!topWindow) {
     return;
   }
--- a/dom/audiochannel/AudioChannelService.h
+++ b/dom/audiochannel/AudioChannelService.h
@@ -11,17 +11,18 @@
 #include "nsAutoPtr.h"
 #include "nsIObserver.h"
 #include "nsTObserverArray.h"
 #include "nsTArray.h"
 
 #include "AudioChannelAgent.h"
 #include "nsAttrValue.h"
 #include "mozilla/dom/AudioChannelBinding.h"
-#include "mozilla/Function.h"
+
+#include <functional>
 
 class nsIRunnable;
 class nsPIDOMWindowOuter;
 struct PRLogModuleInfo;
 
 namespace mozilla {
 namespace dom {
 
@@ -190,17 +191,17 @@ public:
   void ChildStatusReceived(uint64_t aChildID, bool aTelephonyChannel,
                            bool aContentOrNormalChannel, bool aAnyChannel);
 
 private:
   AudioChannelService();
   ~AudioChannelService();
 
   void RefreshAgents(nsPIDOMWindowOuter* aWindow,
-                     mozilla::function<void(AudioChannelAgent*)> aFunc);
+                     std::function<void(AudioChannelAgent*)> aFunc);
 
   static void CreateServiceIfNeeded();
 
   /**
    * Shutdown the singleton.
    */
   static void Shutdown();
 
--- a/dom/base/File.cpp
+++ b/dom/base/File.cpp
@@ -153,46 +153,52 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
   NS_INTERFACE_MAP_ENTRY(nsIMutable)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Blob)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Blob)
 
+// A utility function that enforces the spec constraints on the type of a blob:
+// no codepoints outside the ASCII range (otherwise type becomes empty) and
+// lowercase ASCII only.  We can't just use our existing nsContentUtils
+// ASCII-related helpers because we need the "outside ASCII range" check, and we
+// can't use NS_IsAscii because its definition of "ASCII" (chars all <= 0x7E)
+// differs from the file API definition (which excludes control chars).
+static void
+MakeValidBlobType(nsAString& aType)
+{
+  char16_t* iter = aType.BeginWriting();
+  char16_t* end = aType.EndWriting();
+
+  for ( ; iter != end; ++iter) {
+    char16_t c = *iter;
+    if (c < 0x20 || c > 0x7E) {
+      // Non-ASCII char, bail out.
+      aType.Truncate();
+      return;
+    }
+
+    if (c >= 'A' && c <= 'Z') {
+      *iter = c + ('a' - 'A');
+    }
+  }
+}
+
 /* static */ Blob*
 Blob::Create(nsISupports* aParent, BlobImpl* aImpl)
 {
   MOZ_ASSERT(aImpl);
 
   return aImpl->IsFile() ? new File(aParent, aImpl)
                          : new Blob(aParent, aImpl);
 }
 
 /* static */ already_AddRefed<Blob>
-Blob::Create(nsISupports* aParent, const nsAString& aContentType,
-             uint64_t aLength)
-{
-  RefPtr<Blob> blob = Blob::Create(aParent,
-    new BlobImplBase(aContentType, aLength));
-  MOZ_ASSERT(!blob->mImpl->IsFile());
-  return blob.forget();
-}
-
-/* static */ already_AddRefed<Blob>
-Blob::Create(nsISupports* aParent, const nsAString& aContentType,
-             uint64_t aStart, uint64_t aLength)
-{
-  RefPtr<Blob> blob = Blob::Create(aParent,
-    new BlobImplBase(aContentType, aStart, aLength));
-  MOZ_ASSERT(!blob->mImpl->IsFile());
-  return blob.forget();
-}
-
-/* static */ already_AddRefed<Blob>
 Blob::CreateStringBlob(nsISupports* aParent, const nsACString& aData,
                        const nsAString& aContentType)
 {
   RefPtr<BlobImpl> blobImpl = BlobImplString::Create(aData, aContentType);
   RefPtr<Blob> blob = Blob::Create(aParent, blobImpl);
   MOZ_ASSERT(!blob->mImpl->IsFile());
   return blob.forget();
 }
@@ -355,17 +361,19 @@ Blob::WrapObject(JSContext* aCx, JS::Han
 Blob::Constructor(const GlobalObject& aGlobal,
                   const Optional<Sequence<BlobPart>>& aData,
                   const BlobPropertyBag& aBag,
                   ErrorResult& aRv)
 {
   RefPtr<MultipartBlobImpl> impl = new MultipartBlobImpl();
 
   if (aData.WasPassed()) {
-    impl->InitializeBlob(aGlobal.Context(), aData.Value(), aBag.mType,
+    nsAutoString type(aBag.mType);
+    MakeValidBlobType(type);
+    impl->InitializeBlob(aGlobal.Context(), aData.Value(), type,
                          aBag.mEndings == EndingTypes::Native, aRv);
   } else {
     impl->InitializeBlob(aRv);
   }
 
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
@@ -544,17 +552,19 @@ ParseSize(int64_t aSize, int64_t& aStart
 File::Constructor(const GlobalObject& aGlobal,
                   const Sequence<BlobPart>& aData,
                   const nsAString& aName,
                   const FilePropertyBag& aBag,
                   ErrorResult& aRv)
 {
   RefPtr<MultipartBlobImpl> impl = new MultipartBlobImpl(aName);
 
-  impl->InitializeBlob(aGlobal.Context(), aData, aBag.mType, false, aRv);
+  nsAutoString type(aBag.mType);
+  MakeValidBlobType(type);
+  impl->InitializeBlob(aGlobal.Context(), aData, type, false, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
   MOZ_ASSERT(impl->IsFile());
 
   if (aBag.mLastModified.WasPassed()) {
     impl->SetLastModified(aBag.mLastModified.Value());
   }
@@ -635,18 +645,19 @@ BlobImpl::Slice(const Optional<int64_t>&
     return nullptr;
   }
 
   int64_t start = aStart.WasPassed() ? aStart.Value() : 0;
   int64_t end = aEnd.WasPassed() ? aEnd.Value() : (int64_t)thisLength;
 
   ParseSize((int64_t)thisLength, start, end);
 
-  return CreateSlice((uint64_t)start, (uint64_t)(end - start),
-                     aContentType, aRv);
+  nsAutoString type(aContentType);
+  MakeValidBlobType(type);
+  return CreateSlice((uint64_t)start, (uint64_t)(end - start), type, aRv);
 }
 
 ////////////////////////////////////////////////////////////////////////////
 // BlobImpl implementation
 
 NS_IMPL_ISUPPORTS(BlobImpl, BlobImpl)
 
 ////////////////////////////////////////////////////////////////////////////
--- a/dom/base/File.h
+++ b/dom/base/File.h
@@ -60,24 +60,16 @@ public:
 
   typedef OwningArrayBufferOrArrayBufferViewOrBlobOrUSVString BlobPart;
 
   // This creates a Blob or a File based on the type of BlobImpl.
   static Blob*
   Create(nsISupports* aParent, BlobImpl* aImpl);
 
   static already_AddRefed<Blob>
-  Create(nsISupports* aParent, const nsAString& aContentType,
-         uint64_t aLength);
-
-  static already_AddRefed<Blob>
-  Create(nsISupports* aParent, const nsAString& aContentType, uint64_t aStart,
-         uint64_t aLength);
-
-  static already_AddRefed<Blob>
   CreateStringBlob(nsISupports* aParent, const nsACString& aData,
                    const nsAString& aContentType);
 
   // The returned Blob takes ownership of aMemoryBuffer. aMemoryBuffer will be
   // freed by free so it must be allocated by malloc or something
   // compatible with it.
   static already_AddRefed<Blob>
   CreateMemoryBlob(nsISupports* aParent, void* aMemoryBuffer, uint64_t aLength,
--- a/dom/base/IdleRequest.cpp
+++ b/dom/base/IdleRequest.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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 "IdleRequest.h"
 
-#include "mozilla/Function.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/dom/IdleDeadline.h"
 #include "mozilla/dom/Performance.h"
 #include "mozilla/dom/PerformanceTiming.h"
 #include "mozilla/dom/WindowBinding.h"
 #include "nsComponentManagerUtils.h"
 #include "nsGlobalWindow.h"
 #include "nsISupportsPrimitives.h"
--- a/dom/base/WebSocket.cpp
+++ b/dom/base/WebSocket.cpp
@@ -114,31 +114,29 @@ public:
 
   void AssertIsOnTargetThread() const
   {
     MOZ_ASSERT(IsTargetThread());
   }
 
   bool IsTargetThread() const;
 
-  void Init(JSContext* aCx,
-            nsIPrincipal* aPrincipal,
-            bool aIsServerSide,
-            const nsAString& aURL,
-            nsTArray<nsString>& aProtocolArray,
-            const nsACString& aScriptFile,
-            uint32_t aScriptLine,
-            uint32_t aScriptColumn,
-            ErrorResult& aRv,
-            bool* aConnectionFailed);
-
-  void AsyncOpen(nsIPrincipal* aPrincipal, uint64_t aInnerWindowID,
-                 nsITransportProvider* aTransportProvider,
-                 const nsACString& aNegotiatedExtensions,
-                 ErrorResult& aRv);
+  nsresult Init(JSContext* aCx,
+                nsIPrincipal* aPrincipal,
+                bool aIsServerSide,
+                const nsAString& aURL,
+                nsTArray<nsString>& aProtocolArray,
+                const nsACString& aScriptFile,
+                uint32_t aScriptLine,
+                uint32_t aScriptColumn,
+                bool* aConnectionFailed);
+
+  nsresult AsyncOpen(nsIPrincipal* aPrincipal, uint64_t aInnerWindowID,
+                     nsITransportProvider* aTransportProvider,
+                     const nsACString& aNegotiatedExtensions);
 
   nsresult ParseURL(const nsAString& aURL);
   nsresult InitializeConnection(nsIPrincipal* aPrincipal);
 
   // These methods when called can release the WebSocket object
   void FailConnection(uint16_t reasonCode,
                       const nsACString& aReasonString = EmptyCString());
   nsresult CloseConnection(uint16_t reasonCode,
@@ -1059,148 +1057,161 @@ protected:
 
 class InitRunnable final : public WebSocketMainThreadRunnable
 {
 public:
   InitRunnable(WebSocketImpl* aImpl, bool aIsServerSide,
                const nsAString& aURL,
                nsTArray<nsString>& aProtocolArray,
                const nsACString& aScriptFile, uint32_t aScriptLine,
-               uint32_t aScriptColumn,
-               ErrorResult& aRv, bool* aConnectionFailed)
+               uint32_t aScriptColumn, bool* aConnectionFailed)
     : WebSocketMainThreadRunnable(aImpl->mWorkerPrivate,
                                   NS_LITERAL_CSTRING("WebSocket :: init"))
     , mImpl(aImpl)
     , mIsServerSide(aIsServerSide)
     , mURL(aURL)
     , mProtocolArray(aProtocolArray)
     , mScriptFile(aScriptFile)
     , mScriptLine(aScriptLine)
     , mScriptColumn(aScriptColumn)
-    , mRv(aRv)
     , mConnectionFailed(aConnectionFailed)
+    , mErrorCode(NS_OK)
   {
     MOZ_ASSERT(mWorkerPrivate);
     mWorkerPrivate->AssertIsOnWorkerThread();
   }
 
+  nsresult
+  ErrorCode() const
+  {
+    return mErrorCode;
+  }
+
 protected:
   virtual bool InitWithWindow(nsPIDOMWindowInner* aWindow) override
   {
     AutoJSAPI jsapi;
     if (NS_WARN_IF(!jsapi.Init(aWindow))) {
-      mRv.Throw(NS_ERROR_FAILURE);
+      mErrorCode = NS_ERROR_FAILURE;
       return true;
     }
 
     ClearException ce(jsapi.cx());
 
     nsIDocument* doc = aWindow->GetExtantDoc();
     if (!doc) {
-      mRv.Throw(NS_ERROR_FAILURE);
+      mErrorCode = NS_ERROR_FAILURE;
       return true;
     }
 
     nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
     if (!principal) {
-      mRv.Throw(NS_ERROR_FAILURE);
+      mErrorCode = NS_ERROR_FAILURE;
       return true;
     }
 
-    mImpl->Init(jsapi.cx(), principal, mIsServerSide, mURL, mProtocolArray,
-                mScriptFile, mScriptLine, mScriptColumn, mRv,
-                mConnectionFailed);
+    mErrorCode =
+      mImpl->Init(jsapi.cx(), principal, mIsServerSide, mURL, mProtocolArray,
+                  mScriptFile, mScriptLine, mScriptColumn, mConnectionFailed);
     return true;
   }
 
   virtual bool InitWindowless(WorkerPrivate* aTopLevelWorkerPrivate) override
   {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(aTopLevelWorkerPrivate && !aTopLevelWorkerPrivate->GetWindow());
 
-    mImpl->Init(nullptr, aTopLevelWorkerPrivate->GetPrincipal(), mIsServerSide,
-                mURL, mProtocolArray, mScriptFile, mScriptLine, mScriptColumn,
-                mRv, mConnectionFailed);
+    mErrorCode =
+      mImpl->Init(nullptr, aTopLevelWorkerPrivate->GetPrincipal(),
+                  mIsServerSide, mURL, mProtocolArray, mScriptFile, mScriptLine,
+                  mScriptColumn, mConnectionFailed);
     return true;
   }
 
   // Raw pointer. This worker runs synchronously.
   WebSocketImpl* mImpl;
 
   bool mIsServerSide;
   const nsAString& mURL;
   nsTArray<nsString>& mProtocolArray;
   nsCString mScriptFile;
   uint32_t mScriptLine;
   uint32_t mScriptColumn;
-  ErrorResult& mRv;
   bool* mConnectionFailed;
+  nsresult mErrorCode;
 };
 
 class AsyncOpenRunnable final : public WebSocketMainThreadRunnable
 {
 public:
-  AsyncOpenRunnable(WebSocketImpl* aImpl, ErrorResult& aRv)
+  explicit AsyncOpenRunnable(WebSocketImpl* aImpl)
     : WebSocketMainThreadRunnable(aImpl->mWorkerPrivate,
                                   NS_LITERAL_CSTRING("WebSocket :: AsyncOpen"))
     , mImpl(aImpl)
-    , mRv(aRv)
+    , mErrorCode(NS_OK)
   {
     MOZ_ASSERT(mWorkerPrivate);
     mWorkerPrivate->AssertIsOnWorkerThread();
   }
 
+  nsresult
+  ErrorCode() const
+  {
+    return mErrorCode;
+  }
+
 protected:
   virtual bool InitWithWindow(nsPIDOMWindowInner* aWindow) override
   {
     AssertIsOnMainThread();
     MOZ_ASSERT(aWindow);
 
     nsIDocument* doc = aWindow->GetExtantDoc();
     if (!doc) {
-      mRv.Throw(NS_ERROR_FAILURE);
+      mErrorCode = NS_ERROR_FAILURE;
       return true;
     }
 
     nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
     if (!principal) {
-      mRv.Throw(NS_ERROR_FAILURE);
+      mErrorCode = NS_ERROR_FAILURE;
       return true;
     }
 
     uint64_t windowID = 0;
     nsCOMPtr<nsPIDOMWindowOuter> topWindow = aWindow->GetScriptableTop();
     nsCOMPtr<nsPIDOMWindowInner> topInner;
     if (topWindow) {
       topInner = topWindow->GetCurrentInnerWindow();
     }
 
     if (topInner) {
       windowID = topInner->WindowID();
     }
 
-    mImpl->AsyncOpen(principal, windowID, nullptr, EmptyCString(), mRv);
+    mErrorCode = mImpl->AsyncOpen(principal, windowID, nullptr, EmptyCString());
     return true;
   }
 
   virtual bool InitWindowless(WorkerPrivate* aTopLevelWorkerPrivate) override
   {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(aTopLevelWorkerPrivate && !aTopLevelWorkerPrivate->GetWindow());
 
-    mImpl->AsyncOpen(aTopLevelWorkerPrivate->GetPrincipal(), 0, nullptr,
-                     EmptyCString(), mRv);
+    mErrorCode =
+      mImpl->AsyncOpen(aTopLevelWorkerPrivate->GetPrincipal(), 0, nullptr,
+                       EmptyCString());
     return true;
   }
 
 private:
   // Raw pointer. This worker runs synchronously.
   WebSocketImpl* mImpl;
 
-  ErrorResult& mRv;
+  nsresult mErrorCode;
 };
 
 } // namespace
 
 already_AddRefed<WebSocket>
 WebSocket::ConstructorCommon(const GlobalObject& aGlobal,
                              const nsAString& aUrl,
                              const Sequence<nsString>& aProtocols,
@@ -1265,19 +1276,20 @@ WebSocket::ConstructorCommon(const Globa
   }
 
   RefPtr<WebSocket> webSocket = new WebSocket(ownerWindow);
   RefPtr<WebSocketImpl> webSocketImpl = webSocket->mImpl;
 
   bool connectionFailed = true;
 
   if (NS_IsMainThread()) {
-    webSocketImpl->Init(aGlobal.Context(), principal, !!aTransportProvider,
-                        aUrl, protocolArray, EmptyCString(),
-                        0, 0, aRv, &connectionFailed);
+    aRv =
+      webSocketImpl->Init(aGlobal.Context(), principal, !!aTransportProvider,
+                          aUrl, protocolArray, EmptyCString(), 0, 0,
+                          &connectionFailed);
   } else {
     // In workers we have to keep the worker alive using a workerHolder in order
     // to dispatch messages correctly.
     if (!webSocketImpl->RegisterWorkerHolder()) {
       aRv.Throw(NS_ERROR_FAILURE);
       return nullptr;
     }
 
@@ -1286,18 +1298,23 @@ WebSocket::ConstructorCommon(const Globa
     if (!JS::DescribeScriptedCaller(aGlobal.Context(), &file, &lineno,
                                     &column)) {
       NS_WARNING("Failed to get line number and filename in workers.");
     }
 
     RefPtr<InitRunnable> runnable =
       new InitRunnable(webSocketImpl, !!aTransportProvider, aUrl,
                        protocolArray, nsDependentCString(file.get()), lineno,
-                       column, aRv, &connectionFailed);
+                       column, &connectionFailed);
     runnable->Dispatch(aRv);
+    if (NS_WARN_IF(aRv.Failed())) {
+      return nullptr;
+    }
+
+    aRv = runnable->ErrorCode();
   }
 
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   // It can be that we have been already disconnected because the WebSocket is
   // gone away while we where initializing the webSocket.
@@ -1364,24 +1381,29 @@ WebSocket::ConstructorCommon(const Globa
     if (topWindow) {
       topInner = topWindow->GetCurrentInnerWindow();
     }
 
     if (topInner) {
       windowID = topInner->WindowID();
     }
 
-    webSocket->mImpl->AsyncOpen(principal, windowID, aTransportProvider,
-                                aNegotiatedExtensions, aRv);
+    aRv = webSocket->mImpl->AsyncOpen(principal, windowID, aTransportProvider,
+                                      aNegotiatedExtensions);
   } else {
     MOZ_ASSERT(!aTransportProvider && aNegotiatedExtensions.IsEmpty(),
                "not yet implemented");
     RefPtr<AsyncOpenRunnable> runnable =
-      new AsyncOpenRunnable(webSocket->mImpl, aRv);
+      new AsyncOpenRunnable(webSocket->mImpl);
     runnable->Dispatch(aRv);
+    if (NS_WARN_IF(aRv.Failed())) {
+      return nullptr;
+    }
+
+    aRv = runnable->ErrorCode();
   }
 
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   // It can be that we have been already disconnected because the WebSocket is
   // gone away while we where initializing the webSocket.
@@ -1462,61 +1484,53 @@ WebSocket::DisconnectFromOwner()
 
   DontKeepAliveAnyMore();
 }
 
 //-----------------------------------------------------------------------------
 // WebSocketImpl:: initialization
 //-----------------------------------------------------------------------------
 
-void
+nsresult
 WebSocketImpl::Init(JSContext* aCx,
                     nsIPrincipal* aPrincipal,
                     bool aIsServerSide,
                     const nsAString& aURL,
                     nsTArray<nsString>& aProtocolArray,
                     const nsACString& aScriptFile,
                     uint32_t aScriptLine,
                     uint32_t aScriptColumn,
-                    ErrorResult& aRv,
                     bool* aConnectionFailed)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aPrincipal);
 
   mService = WebSocketEventService::GetOrCreate();
 
   // We need to keep the implementation alive in case the init disconnects it
   // because of some error.
   RefPtr<WebSocketImpl> kungfuDeathGrip = this;
 
   // Attempt to kill "ghost" websocket: but usually too early for check to fail
-  aRv = mWebSocket->CheckInnerWindowCorrectness();
-  if (NS_WARN_IF(aRv.Failed())) {
-    return;
-  }
+  nsresult rv = mWebSocket->CheckInnerWindowCorrectness();
+  NS_ENSURE_SUCCESS(rv, rv);
 
   // Shut down websocket if window is frozen or destroyed (only needed for
   // "ghost" websockets--see bug 696085)
   if (!mWorkerPrivate) {
     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
     if (NS_WARN_IF(!os)) {
-      aRv.Throw(NS_ERROR_FAILURE);
-      return;
+      return NS_ERROR_FAILURE;
     }
 
-    aRv = os->AddObserver(this, DOM_WINDOW_DESTROYED_TOPIC, true);
-    if (NS_WARN_IF(aRv.Failed())) {
-      return;
-    }
-
-    aRv = os->AddObserver(this, DOM_WINDOW_FROZEN_TOPIC, true);
-    if (NS_WARN_IF(aRv.Failed())) {
-      return;
-    }
+    rv = os->AddObserver(this, DOM_WINDOW_DESTROYED_TOPIC, true);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = os->AddObserver(this, DOM_WINDOW_FROZEN_TOPIC, true);
+    NS_ENSURE_SUCCESS(rv, rv);
   }
 
   if (mWorkerPrivate) {
     mScriptFile = aScriptFile;
     mScriptLine = aScriptLine;
     mScriptColumn = aScriptColumn;
   } else {
     MOZ_ASSERT(aCx);
@@ -1535,28 +1549,23 @@ WebSocketImpl::Init(JSContext* aCx,
   // If we don't have aCx, we are window-less, so we don't have a
   // inner-windowID. This can happen in sharedWorkers and ServiceWorkers or in
   // DedicateWorkers created by JSM.
   if (aCx) {
     mInnerWindowID = nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(aCx);
   }
 
   // parses the url
-  aRv = ParseURL(PromiseFlatString(aURL));
-  if (NS_WARN_IF(aRv.Failed())) {
-    return;
-  }
+  rv = ParseURL(PromiseFlatString(aURL));
+  NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIDocument> originDoc = mWebSocket->GetDocumentIfCurrent();
   if (!originDoc) {
-    nsresult rv = mWebSocket->CheckInnerWindowCorrectness();
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      aRv.Throw(rv);
-      return;
-    }
+    rv = mWebSocket->CheckInnerWindowCorrectness();
+    NS_ENSURE_SUCCESS(rv, rv);
   }
   mOriginDocument = do_GetWeakReference(originDoc);
 
   if (!mIsServerSide) {
     nsCOMPtr<nsIURI> uri;
     {
       nsresult rv = NS_NewURI(getter_AddRefs(uri), mURI);
 
@@ -1569,51 +1578,47 @@ WebSocketImpl::Init(JSContext* aCx,
 
     // The 'real' nsHttpChannel of the websocket gets opened in the parent.
     // Since we don't serialize the CSP within child and parent and also not
     // the context, we have to perform content policy checks here instead of
     // AsyncOpen2().
     // Please note that websockets can't follow redirects, hence there is no
     // need to perform a CSP check after redirects.
     int16_t shouldLoad = nsIContentPolicy::ACCEPT;
-    aRv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_WEBSOCKET,
-                                    uri,
-                                    aPrincipal,
-                                    originDoc,
-                                    EmptyCString(),
-                                    nullptr,
-                                    &shouldLoad,
-                                    nsContentUtils::GetContentPolicy(),
-                                    nsContentUtils::GetSecurityManager());
-
-    if (NS_WARN_IF(aRv.Failed())) {
-      return;
-    }
+    rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_WEBSOCKET,
+                                   uri,
+                                   aPrincipal,
+                                   originDoc,
+                                   EmptyCString(),
+                                   nullptr,
+                                   &shouldLoad,
+                                   nsContentUtils::GetContentPolicy(),
+                                   nsContentUtils::GetSecurityManager());
+    NS_ENSURE_SUCCESS(rv, rv);
 
     if (NS_CP_REJECTED(shouldLoad)) {
       // Disallowed by content policy
-      aRv.Throw(NS_ERROR_CONTENT_BLOCKED);
-      return;
+      return NS_ERROR_CONTENT_BLOCKED;
     }
   }
 
   // Potentially the page uses the CSP directive 'upgrade-insecure-requests'.
   // In such a case we have to upgrade ws: to wss: and also update mSecure
   // to reflect that upgrade. Please note that we can not upgrade from ws:
   // to wss: before performing content policy checks because CSP needs to
   // send reports in case the scheme is about to be upgraded.
   if (!mIsServerSide && !mSecure && originDoc &&
       originDoc->GetUpgradeInsecureRequests(false)) {
     // let's use the old specification before the upgrade for logging
     NS_ConvertUTF8toUTF16 reportSpec(mURI);
 
     // upgrade the request from ws:// to wss:// and mark as secure
     mURI.ReplaceSubstring("ws://", "wss://");
     if (NS_WARN_IF(mURI.Find("wss://") != 0)) {
-      return;
+      return NS_OK;
     }
     mSecure = true;
 
     const char16_t* params[] = { reportSpec.get(), u"wss" };
     CSP_LogLocalizedStr(u"upgradeInsecureRequest",
                         params, ArrayLength(params),
                         EmptyString(), // aSourceFile
                         EmptyString(), // aScriptSample
@@ -1651,95 +1656,86 @@ WebSocketImpl::Init(JSContext* aCx,
 
         if (!isNullPrincipal) {
           break;
         }
 
         if (!innerWindow) {
           innerWindow = do_QueryInterface(globalObject);
           if (NS_WARN_IF(!innerWindow)) {
-            aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
-            return;
+            return NS_ERROR_DOM_SECURITY_ERR;
           }
         }
 
         nsCOMPtr<nsPIDOMWindowOuter> parentWindow =
           innerWindow->GetScriptableParent();
         if (NS_WARN_IF(!parentWindow)) {
-          aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
-          return;
+          return NS_ERROR_DOM_SECURITY_ERR;
         }
 
         nsCOMPtr<nsPIDOMWindowInner> currentInnerWindow =
           parentWindow->GetCurrentInnerWindow();
         if (NS_WARN_IF(!currentInnerWindow)) {
-          aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
-          return;
+          return NS_ERROR_DOM_SECURITY_ERR;
         }
 
         // We are at the top. Let's see if we have an opener window.
         if (innerWindow == currentInnerWindow) {
           ErrorResult error;
           parentWindow =
             nsGlobalWindow::Cast(innerWindow)->GetOpenerWindow(error);
           if (NS_WARN_IF(error.Failed())) {
             error.SuppressException();
-            aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
-            return;
+            return NS_ERROR_DOM_SECURITY_ERR;
           }
 
           if (!parentWindow) {
             break;
           }
 
           currentInnerWindow = parentWindow->GetCurrentInnerWindow();
           if (NS_WARN_IF(!currentInnerWindow)) {
-            aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
-            return;
+            return NS_ERROR_DOM_SECURITY_ERR;
           }
 
           MOZ_ASSERT(currentInnerWindow != innerWindow);
         }
 
         innerWindow = currentInnerWindow;
 
         nsCOMPtr<nsIDocument> document = innerWindow->GetExtantDoc();
         if (NS_WARN_IF(!document)) {
-          aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
-          return;
+          return NS_ERROR_DOM_SECURITY_ERR;
         }
 
         principal = document->NodePrincipal();
       }
     }
 
     if (principal) {
       principal->GetURI(getter_AddRefs(originURI));
     }
 
     if (originURI) {
       bool originIsHttps = false;
-      aRv = originURI->SchemeIs("https", &originIsHttps);
-      if (NS_WARN_IF(aRv.Failed())) {
-        return;
-      }
+      rv = originURI->SchemeIs("https", &originIsHttps);
+      NS_ENSURE_SUCCESS(rv, rv);
+
       if (originIsHttps) {
-        aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
-        return;
+        return NS_ERROR_DOM_SECURITY_ERR;
       }
     }
   }
 
   // Assign the sub protocol list and scan it for illegal values
   for (uint32_t index = 0; index < aProtocolArray.Length(); ++index) {
     for (uint32_t i = 0; i < aProtocolArray[index].Length(); ++i) {
       if (aProtocolArray[index][i] < static_cast<char16_t>(0x0021) ||
           aProtocolArray[index][i] > static_cast<char16_t>(0x007E)) {
-        aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
-        return;
+        return NS_ERROR_DOM_SYNTAX_ERR;
       }
     }
 
     if (!mRequestedProtocolList.IsEmpty()) {
       mRequestedProtocolList.AppendLiteral(", ");
     }
 
     AppendUTF16toUTF8(aProtocolArray[index], mRequestedProtocolList);
@@ -1748,55 +1744,54 @@ WebSocketImpl::Init(JSContext* aCx,
   // the constructor should throw a SYNTAX_ERROR only if it fails to parse the
   // url parameter, so don't throw if InitializeConnection fails, and call
   // onerror/onclose asynchronously
   if (NS_FAILED(InitializeConnection(aPrincipal))) {
     *aConnectionFailed = true;
   } else {
     *aConnectionFailed = false;
   }
+
+  return NS_OK;
 }
 
-void
+nsresult
 WebSocketImpl::AsyncOpen(nsIPrincipal* aPrincipal, uint64_t aInnerWindowID,
                          nsITransportProvider* aTransportProvider,
-                         const nsACString& aNegotiatedExtensions,
-                         ErrorResult& aRv)
+                         const nsACString& aNegotiatedExtensions)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Not running on main thread");
   MOZ_ASSERT_IF(!aTransportProvider, aNegotiatedExtensions.IsEmpty());
 
   nsCString asciiOrigin;
-  aRv = nsContentUtils::GetASCIIOrigin(aPrincipal, asciiOrigin);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return;
-  }
+  nsresult rv = nsContentUtils::GetASCIIOrigin(aPrincipal, asciiOrigin);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   if (aTransportProvider) {
-    aRv = mChannel->SetServerParameters(aTransportProvider, aNegotiatedExtensions);
-    if (NS_WARN_IF(aRv.Failed())) {
-      return;
-    }
+    rv = mChannel->SetServerParameters(aTransportProvider,
+                                       aNegotiatedExtensions);
+    NS_ENSURE_SUCCESS(rv, rv);
   }
 
   ToLowerCase(asciiOrigin);
 
   nsCOMPtr<nsIURI> uri;
   if (!aTransportProvider) {
-    aRv = NS_NewURI(getter_AddRefs(uri), mURI);
-    MOZ_ASSERT(!aRv.Failed());
+    rv = NS_NewURI(getter_AddRefs(uri), mURI);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
   }
 
-  aRv = mChannel->AsyncOpen(uri, asciiOrigin, aInnerWindowID, this, nullptr);
-  if (NS_WARN_IF(aRv.Failed())) {
-    aRv.Throw(NS_ERROR_CONTENT_BLOCKED);
-    return;
+  rv = mChannel->AsyncOpen(uri, asciiOrigin, aInnerWindowID, this, nullptr);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return NS_ERROR_CONTENT_BLOCKED;
   }
 
   mInnerWindowID = aInnerWindowID;
+
+  return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // WebSocketImpl methods:
 //-----------------------------------------------------------------------------
 
 class nsAutoCloseWS final
 {
--- a/dom/base/nsDataDocumentContentPolicy.cpp
+++ b/dom/base/nsDataDocumentContentPolicy.cpp
@@ -70,17 +70,22 @@ nsDataDocumentContentPolicy::ShouldLoad(
   if (doc->IsLoadedAsData()) {
     // ...but let static (print/print preview) documents to load fonts.
     if (!doc->IsStaticDocument() || aContentType != nsIContentPolicy::TYPE_FONT) {
       *aDecision = nsIContentPolicy::REJECT_TYPE;
       return NS_OK;
     }
   }
 
-  if (doc->IsBeingUsedAsImage()) {
+  nsIDocument* docToCheckForImage = doc->GetDisplayDocument();
+  if (!docToCheckForImage) {
+    docToCheckForImage = doc;
+  }
+
+  if (docToCheckForImage->IsBeingUsedAsImage()) {
     // We only allow SVG images to load content from URIs that are local and
     // also satisfy one of the following conditions:
     //  - URI inherits security context, e.g. data URIs
     //   OR
     //  - URI loadable by subsumers, e.g. blob URIs
     // Any URI that doesn't meet these requirements will be rejected below.
     if (!(HasFlags(aContentLocation,
                    nsIProtocolHandler::URI_IS_LOCAL_RESOURCE) &&
--- a/dom/base/nsIScriptTimeoutHandler.h
+++ b/dom/base/nsIScriptTimeoutHandler.h
@@ -4,17 +4,16 @@
  * 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/. */
 #ifndef nsIScriptTimeoutHandler_h___
 #define nsIScriptTimeoutHandler_h___
 
 #include "nsITimeoutHandler.h"
 #include "nsTArray.h"
 #include "js/TypeDecls.h"
-#include "mozilla/Function.h"
 #include "mozilla/Maybe.h"
 
 namespace mozilla {
 namespace dom {
 class Function;
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/base/nsJSTimeoutHandler.cpp
+++ b/dom/base/nsJSTimeoutHandler.cpp
@@ -2,17 +2,16 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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 <algorithm>
 
 #include "mozilla/Attributes.h"
-#include "mozilla/Function.h"
 #include "mozilla/Likely.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/dom/FunctionBinding.h"
 #include "nsAXPCNativeCallContext.h"
 #include "nsCOMPtr.h"
 #include "nsContentUtils.h"
 #include "nsError.h"
 #include "nsGlobalWindow.h"
new file mode 100644
--- /dev/null
+++ b/dom/base/test/file_timer_flood.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<script>
+let count = 0;
+function cb() {
+  count += 1;
+  // Notify our parent that we are ready once the timer flood has
+  // warmed up.
+  if (count === 10000) {
+    window.parent.postMessage('STARTED', '*');
+  }
+  setTimeout(cb, 0);
+  setTimeout(cb, 0);
+}
+addEventListener('load', cb);
+</script>
+</body>
+</html>
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -154,16 +154,17 @@ support-files =
   file_mozfiledataurl_audio.ogg
   file_mozfiledataurl_doc.html
   file_mozfiledataurl_img.jpg
   file_mozfiledataurl_inner.html
   file_mozfiledataurl_text.txt
   file_record_orientation.html
   file_restrictedEventSource.sjs
   file_simplecontentpolicy.js
+  file_timer_flood.html
   file_websocket_basic_wsh.py
   file_websocket_hello_wsh.py
   file_websocket_http_resource.txt
   file_websocket_permessage_deflate_wsh.py
   file_websocket_permessage_deflate_disabled_wsh.py
   file_websocket_permessage_deflate_rejected_wsh.py
   file_websocket_permessage_deflate_params_wsh.py
   file_websocket_wsh.py
@@ -667,16 +668,17 @@ skip-if = (toolkit == 'android') # Andro
 [test_iframe_referrer.html]
 [test_iframe_referrer_changing.html]
 [test_iframe_referrer_invalid.html]
 [test_Image_constructor.html]
 [test_img_referrer.html]
 [test_innersize_scrollport.html]
 [test_integer_attr_with_leading_zero.html]
 [test_intersectionobservers.html]
+skip-if = true # Track Bug 1320704
 [test_ipc_messagemanager_blob.html]
 [test_link_prefetch.html]
 skip-if = !e10s # Track Bug 1281415
 [test_link_stylesheet.html]
 [test_messagemanager_targetchain.html]
 [test_meta_viewport0.html]
 skip-if = (os != 'android')    # meta-viewport tag support is mobile-only
 [test_meta_viewport1.html]
@@ -759,16 +761,17 @@ skip-if = debug == false
 [test_settimeout_inner.html]
 [test_setTimeoutWith0.html]
 [test_setting_opener.html]
 [test_simplecontentpolicy.html]
 skip-if = e10s # Bug 1156489.
 [test_text_wholeText.html]
 [test_textnode_normalize_in_selection.html]
 [test_textnode_split_in_selection.html]
+[test_timer_flood.html]
 [test_title.html]
 [test_treewalker_nextsibling.xml]
 [test_user_select.html]
 skip-if = toolkit == 'android'
 [test_viewport_scroll.html]
 [test_viewsource_forbidden_in_object.html]
 [test_w3element_traversal.html]
 [test_w3element_traversal.xhtml]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_timer_flood.html
@@ -0,0 +1,116 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="UTF-8">
+  <title>Test Behavior During Timer Flood</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+
+function onLoad() {
+  return new Promise(resolve => {
+    addEventListener('load', resolve, { once: true });
+  });
+}
+
+// Create a frame that executes a timer flood.  The frame signals
+// that is ready once the flood has had a chance to warm up.
+function withFloodFrame() {
+  return new Promise(resolve => {
+    let frame = document.createElement('iframe');
+    addEventListener('message', function onMsg(evt) {
+      if (evt.data === 'STARTED') {
+        removeEventListener('message', onMsg);
+        resolve(frame);
+      }
+    });
+    frame.src = 'file_timer_flood.html';
+    document.body.appendChild(frame);
+  });
+}
+
+// Test that we can load documents during a timer flood.
+function testFrameLoad() {
+  return new Promise(resolve => {
+    let frame = document.createElement('iframe');
+    frame.addEventListener('load', _ => {
+      frame.remove();
+      resolve();
+    }, { once: true });
+    document.body.appendChild(frame);
+  });
+}
+
+// Test that we can perform network requests while a timer flood
+// is occuring.
+function testFetch(url) {
+  return fetch(url).then(response => {
+    return response.text();
+  });
+}
+
+// Test that we can run animations for 5 seconds while a timer
+// flood is occuring.
+function testRequestAnimationFrame() {
+  return new Promise(resolve => {
+    let remainingFrames = 5 * 60;
+    function nextFrame() {
+      remainingFrames -= 1;
+      if (remainingFrames > 0) {
+        requestAnimationFrame(nextFrame);
+      } else {
+        resolve();
+      }
+    };
+    requestAnimationFrame(nextFrame);
+  });
+}
+
+let floodFrame;
+
+onLoad().then(_ => {
+  // Start a timer flood in a frame.
+  return withFloodFrame();
+}).then(frame => {
+  floodFrame = frame;
+
+  // Next we are going to start a bunch of asynchronous work that we
+  // expect to complete in spite of the timer flood.  The type of work
+  // is a bit arbitrary, but is chosen to reflect the kinds of things
+  // we would like the browser to be able to do even when pages are
+  // abusing timers.  Feel free to add more types of work here, but
+  // think carefully before removing anything.
+  let tests = [];
+
+  // Verify we can perform a variety of work while the timer flood
+  // is running.
+  for (let i = 0; i < 20; ++i) {
+    tests.push(testFrameLoad());
+    tests.push(testFetch('file_timer_flood.html'));
+  }
+  // Verify that animations still work while the timer flood is running.
+  // Note that we do one long run of animations instead of parallel runs
+  // like the other activities because of the way requestAnimationFrame()
+  // is scheduled.  Parallel animations would not result in any additional
+  // runnables be placed on the event queue.
+  tests.push(testRequestAnimationFrame());
+
+  // Wait for all tests to finish.  If we do not handle the timer flood
+  // well then this will likely time out.
+  return Promise.all(tests);
+}).then(_ => {
+  ok(true, 'completed tests without timing out');
+  floodFrame.remove();
+  SimpleTest.finish();
+});
+</script>
+</pre>
+</body>
+</html>
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1072,16 +1072,21 @@ DOMInterfaces = {
     'headerFile': 'WebGLActiveInfo.h'
 },
 
 'WebGLBuffer': {
     'nativeType': 'mozilla::WebGLBuffer',
     'headerFile': 'WebGLBuffer.h'
 },
 
+'WEBGL_compressed_texture_astc': {
+    'nativeType': 'mozilla::WebGLExtensionCompressedTextureASTC',
+    'headerFile': 'WebGLExtensions.h'
+},
+
 'WEBGL_compressed_texture_atc': {
     'nativeType': 'mozilla::WebGLExtensionCompressedTextureATC',
     'headerFile': 'WebGLExtensions.h'
 },
 
 'WEBGL_compressed_texture_etc': {
     'nativeType': 'mozilla::WebGLExtensionCompressedTextureES3',
     'headerFile': 'WebGLExtensions.h'
--- a/dom/cache/TypeUtils.cpp
+++ b/dom/cache/TypeUtils.cpp
@@ -258,19 +258,22 @@ TypeUtils::ToResponse(const CacheRespons
 
   RefPtr<InternalResponse> ir = new InternalResponse(aIn.status(),
                                                        aIn.statusText());
   ir->SetURLList(aIn.urlList());
 
   RefPtr<InternalHeaders> internalHeaders =
     ToInternalHeaders(aIn.headers(), aIn.headersGuard());
   ErrorResult result;
-  ir->Headers()->SetGuard(aIn.headersGuard(), result);
+
+  // Be careful to fill the headers before setting the guard in order to
+  // correctly re-create the original headers.
+  ir->Headers()->Fill(*internalHeaders, result);
   MOZ_ASSERT(!result.Failed());
-  ir->Headers()->Fill(*internalHeaders, result);
+  ir->Headers()->SetGuard(aIn.headersGuard(), result);
   MOZ_ASSERT(!result.Failed());
 
   ir->InitChannelInfo(aIn.channelInfo());
   if (aIn.principalInfo().type() == mozilla::ipc::OptionalPrincipalInfo::TPrincipalInfo) {
     UniquePtr<mozilla::ipc::PrincipalInfo> info(new mozilla::ipc::PrincipalInfo(aIn.principalInfo().get_PrincipalInfo()));
     ir->SetPrincipalInfo(Move(info));
   }
 
--- a/dom/cache/test/mochitest/mochitest.ini
+++ b/dom/cache/test/mochitest/mochitest.ini
@@ -15,16 +15,17 @@ support-files =
   test_cache_match_vary.js
   vary.sjs
   test_caches.js
   test_cache_keys.js
   test_cache_put.js
   test_cache_requestCache.js
   test_cache_delete.js
   test_cache_put_reorder.js
+  test_cache_redirect.js
   test_cache_https.js
   large_url_list.js
   empty.html
 
 [test_cache.html]
 [test_cache_add.html]
 [test_cache_match_request.html]
 [test_cache_matchAll_request.html]
@@ -32,14 +33,15 @@ support-files =
 [test_cache_match_vary.html]
 [test_caches.html]
 [test_cache_keys.html]
 [test_cache_put.html]
 [test_cache_requestCache.html]
 [test_cache_delete.html]
 [test_cache_put_reorder.html]
 [test_cache_https.html]
+[test_cache_redirect.html]
 [test_cache_restart.html]
 [test_cache_shrink.html]
 [test_cache_orphaned_cache.html]
 [test_cache_orphaned_body.html]
 [test_cache_untrusted.html]
 [test_chrome_constructor.html]
new file mode 100644
--- /dev/null
+++ b/dom/cache/test/mochitest/test_cache_redirect.html
@@ -0,0 +1,20 @@
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Validate Cache storage of redirect responses</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+  <script type="text/javascript" src="driver.js"></script>
+</head>
+<body>
+<iframe id="frame"></iframe>
+<script class="testbody" type="text/javascript">
+  runTests("test_cache_redirect.js")
+    .then(function() {
+      SimpleTest.finish();
+    });
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/cache/test/mochitest/test_cache_redirect.js
@@ -0,0 +1,14 @@
+let cache;
+let url = 'foo.html';
+let redirectURL = 'http://example.com/foo-bar.html';
+caches.open('redirect-' + context).then(c => {
+  cache = c;
+  var response = Response.redirect(redirectURL);
+  is(response.headers.get('Location'), redirectURL);
+  return cache.put(url, response);
+}).then(_ => {
+  return cache.match(url);
+}).then(response => {
+  is(response.headers.get('Location'), redirectURL);
+  testDone();
+});
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -560,17 +560,17 @@ private:
 class AdjustedTarget
 {
 public:
   typedef CanvasRenderingContext2D::ContextState ContextState;
 
   explicit AdjustedTarget(CanvasRenderingContext2D* aCtx,
                           const gfx::Rect *aBounds = nullptr)
   {
-    mTarget = aCtx->mTarget;
+    mTarget = (DrawTarget*)aCtx->mTarget;
 
     // All rects in this function are in the device space of ctx->mTarget.
 
     // In order to keep our temporary surfaces as small as possible, we first
     // calculate what their maximum required bounds would need to be if we
     // were to fill the whole canvas. Everything outside those bounds we don't
     // need to render.
     gfx::Rect r(0, 0, aCtx->mWidth, aCtx->mHeight);
@@ -1715,17 +1715,17 @@ void
 CanvasRenderingContext2D::SetErrorState()
 {
   EnsureErrorTarget();
 
   if (mTarget && mTarget != sErrorTarget) {
     gCanvasAzureMemoryUsed -= mWidth * mHeight * 4;
   }
 
-  mTarget = sErrorTarget;
+  mTarget = (DrawTarget*)sErrorTarget;
   mBufferProvider = nullptr;
 
   // clear transforms, clips, etc.
   SetInitialState();
 }
 
 void
 CanvasRenderingContext2D::RegisterAllocation()
@@ -1970,17 +1970,17 @@ CanvasRenderingContext2D::InitializeWith
 {
   RemovePostRefreshObserver();
   mDocShell = aShell;
   AddPostRefreshObserverIfNecessary();
 
   IntSize size = aTarget->GetSize();
   SetDimensions(size.width, size.height);
 
-  mTarget = aTarget;
+  mTarget = (DrawTarget*)aTarget;
   mBufferProvider = new PersistentBufferProviderBasic(aTarget);
 
   if (mTarget->GetBackendType() == gfx::BackendType::CAIRO) {
     // Cf comment in EnsureTarget
     mTarget->PushClipRect(gfx::Rect(Point(0, 0), Size(mWidth, mHeight)));
   }
 
   return NS_OK;
@@ -3149,16 +3149,18 @@ CanvasRenderingContext2D::BeginPath()
   mPathBuilder = nullptr;
   mDSPathBuilder = nullptr;
   mPathTransformWillUpdate = false;
 }
 
 void
 CanvasRenderingContext2D::Fill(const CanvasWindingRule& aWinding)
 {
+  auto autoNotNull = mTarget.MakeAuto();
+
   EnsureUserSpacePath(aWinding);
 
   if (!mPath) {
     return;
   }
 
   gfx::Rect bounds;
 
@@ -4753,16 +4755,18 @@ CanvasRenderingContext2D::CachedSurfaceF
 void
 CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
                                     double aSx, double aSy, double aSw,
                                     double aSh, double aDx, double aDy,
                                     double aDw, double aDh,
                                     uint8_t aOptional_argc,
                                     ErrorResult& aError)
 {
+  auto autoNotNull = mTarget.MakeAuto();
+
   if (mDrawObserver) {
     mDrawObserver->DidDrawCall(CanvasDrawObserver::DrawCallType::DrawImage);
   }
 
   MOZ_ASSERT(aOptional_argc == 0 || aOptional_argc == 2 || aOptional_argc == 6);
 
   if (!ValidateRect(aDx, aDy, aDw, aDh, true)) {
     return;
@@ -5014,17 +5018,17 @@ CanvasRenderingContext2D::DrawImage(cons
       // waste if sourceRect doesn't cover the whole canvas.
       // We avoid copying the whole canvas by manually copying just the part
       // that we need.
       srcSurf = ExtractSubrect(srcSurf, &sourceRect, mTarget);
     }
 
     AdjustedTarget tempTarget(this, bounds.IsEmpty() ? nullptr : &bounds);
     if (!tempTarget) {
-      gfxDevCrash(LogReason::InvalidDrawTarget) << "Invalid adjusted target in Canvas2D " << gfx::hexa(mTarget) << ", " << NeedToDrawShadow() << NeedToApplyFilter();
+      gfxDevCrash(LogReason::InvalidDrawTarget) << "Invalid adjusted target in Canvas2D " << gfx::hexa((DrawTarget*)mTarget) << ", " << NeedToDrawShadow() << NeedToApplyFilter();
       return;
     }
     tempTarget->DrawSurface(srcSurf,
                   gfx::Rect(aDx, aDy, aDw, aDh),
                   sourceRect,
                   DrawSurfaceOptions(samplingFilter, SamplingBounds::UNBOUNDED),
                   DrawOptions(CurrentState().globalAlpha, UsedOperation(), antialiasMode));
   } else {
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -42,16 +42,128 @@ class HTMLImageElementOrHTMLCanvasElemen
 typedef HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap CanvasImageSource;
 class ImageData;
 class StringOrCanvasGradientOrCanvasPattern;
 class OwningStringOrCanvasGradientOrCanvasPattern;
 class TextMetrics;
 class CanvasFilterChainObserver;
 class CanvasPath;
 
+template<class T>
+struct MaybeNotNull
+{
+  MOZ_IMPLICIT MaybeNotNull() : mWrapped(nullptr), mEnsure(false) {}
+  MOZ_IMPLICIT MaybeNotNull(T&& aValue) : mWrapped(aValue), mEnsure(false) {}
+  ~MaybeNotNull() {}
+
+  void BeginNotNull() {
+    mEnsure = true;
+  }
+
+  void EndNotNull() {
+    mEnsure = false;
+  }
+
+  void MaybeCheckWrapped() {
+    if (mEnsure && !mWrapped) {
+      MOZ_CRASH("GFX: Setting mTarget to nullptr?");
+    }
+  }
+
+  typename T::element_type* operator->() const {
+    return mWrapped.get();
+  }
+
+  already_AddRefed<typename T::element_type> forget() {
+    already_AddRefed<typename T::element_type>&& ret = mWrapped.forget();
+    MaybeCheckWrapped();
+    return Move(ret);
+  }
+
+  MOZ_IMPLICIT operator bool () {
+    return mWrapped;
+  }
+
+  operator T&() {
+    return mWrapped;
+  }
+
+  operator typename T::element_type*() {
+    return mWrapped.get();
+  }
+
+  bool operator!() const {
+    return !mWrapped;
+  }
+
+  MaybeNotNull& operator=(decltype(nullptr)) {
+    mWrapped = nullptr;
+    MaybeCheckWrapped();
+    return *this;
+  }
+
+  template<class U>
+  MaybeNotNull& operator=(U& aOther){
+    mWrapped = aOther;
+    MaybeCheckWrapped();
+    return *this;
+  }
+
+  template<class U>
+  MaybeNotNull& operator=(U&& aOther){
+    mWrapped = aOther;
+    MaybeCheckWrapped();
+    return *this;
+  }
+
+  struct AutoNotNull
+  {
+    MOZ_IMPLICIT AutoNotNull(MaybeNotNull* aMaybe) : mMaybe(aMaybe)
+    {
+      mMaybe->BeginNotNull();
+    }
+
+    ~AutoNotNull()
+    {
+      mMaybe->EndNotNull();
+    }
+
+    MaybeNotNull* mMaybe;
+  };
+
+  AutoNotNull MakeAuto()
+  {
+    return AutoNotNull(this);
+  }
+
+  T mWrapped;
+
+  bool mEnsure;
+};
+
+template<class T, class U>
+  bool operator!=(const MaybeNotNull<T>& aT, const U& aU) {
+  return aT.mWrapped != aU;
+}
+
+template<class T, class U>
+  bool operator==(const MaybeNotNull<T>& aT, const U& aU) {
+  return aT.mWrapped == aU;
+}
+
+template<class T, class U>
+  bool operator||(const MaybeNotNull<T>& aT, const U& aU) {
+  return aT.mWrapped || aU;
+}
+
+template<class T, class U>
+  bool operator||(const T& aT, const MaybeNotNull<U>& aU) {
+  return aT || aU.mWrapped;
+}
+
 extern const mozilla::gfx::Float SIGMA_MAX;
 
 template<typename T> class Optional;
 
 struct CanvasBidiProcessor;
 class CanvasRenderingContext2DUserData;
 class CanvasDrawObserver;
 class CanvasShutdownObserver;
@@ -681,17 +793,17 @@ protected:
    * rendering.
    */
   void ReturnTarget(bool aForceReset = false);
 
   /**
    * Check if the target is valid after calling EnsureTarget.
    */
   bool IsTargetValid() const {
-    return mTarget && mTarget != sErrorTarget;
+    return !!mTarget && mTarget != sErrorTarget;
   }
 
   /**
     * Returns the surface format this canvas should be allocated using. Takes
     * into account mOpaque, platform requirements, etc.
     */
   mozilla::gfx::SurfaceFormat GetSurfaceFormat() const;
 
@@ -766,17 +878,17 @@ protected:
   nsTArray<CanvasRenderingContext2DUserData*> mUserDatas;
 
   // If mCanvasElement is not provided, then a docshell is
   nsCOMPtr<nsIDocShell> mDocShell;
 
   // This is created lazily so it is necessary to call EnsureTarget before
   // accessing it. In the event of an error it will be equal to
   // sErrorTarget.
-  RefPtr<mozilla::gfx::DrawTarget> mTarget;
+  MaybeNotNull<RefPtr<mozilla::gfx::DrawTarget>> mTarget;
 
   RefPtr<mozilla::layers::PersistentBufferProvider> mBufferProvider;
 
   uint32_t SkiaGLTex() const;
 
   // This observes our draw calls at the beginning of the canvas
   // lifetime and switches to software or GPU mode depending on
   // what it thinks is best
--- a/dom/canvas/ImageBitmapUtils.cpp
+++ b/dom/canvas/ImageBitmapUtils.cpp
@@ -4,19 +4,20 @@
  * 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 "ImageBitmapUtils.h"
 #include "ImageBitmapColorUtils.h"
 #include "ImageContainer.h"
 #include "libyuv.h"
 #include "mozilla/dom/ImageBitmapBinding.h"
-#include "mozilla/Function.h"
 #include "mozilla/gfx/2D.h"
 
+#include <functional>
+
 using namespace libyuv;
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace dom {
 namespace imagebitmapformat {
 
 class Utils;
@@ -320,17 +321,17 @@ Utils::GetUtils(ImageBitmapFormat aForma
 /*
  * Helper functions.
  */
 template<typename SrcType, typename DstType>
 static UniquePtr<ImagePixelLayout>
 CvtSimpleImgToSimpleImg(Utils* aSrcUtils, const SrcType* aSrcBuffer,
                         const ImagePixelLayout* aSrcLayout, DstType* aDstBuffer,
                         ImageBitmapFormat aDstFormat, int aDstChannelCount,
-                        mozilla::function<int (const SrcType*, int, DstType*, int, int, int)> converter)
+                        std::function<int (const SrcType*, int, DstType*, int, int, int)> converter)
 {
   MOZ_ASSERT(aSrcUtils, "Convert color from a null utility object.");
   MOZ_ASSERT(aSrcBuffer, "Convert color from a null buffer.");
   MOZ_ASSERT(aSrcLayout, "Convert color from a null layout.");
   MOZ_ASSERT(aDstBuffer, "Convert color to a null buffer.");
 
   const nsTArray<ChannelPixelLayout>& channels = *aSrcLayout;
   MOZ_ASSERT(channels.Length() == aSrcUtils->GetChannelCount(),
@@ -348,17 +349,17 @@ CvtSimpleImgToSimpleImg(Utils* aSrcUtils
   return CreateDefaultPixelLayout(aDstFormat, channels[0].mWidth,
                                   channels[0].mHeight, dstStride);
 }
 
 static UniquePtr<ImagePixelLayout>
 CvtYUVImgToSimpleImg(Utils* aSrcUtils, const uint8_t* aSrcBuffer,
                      const ImagePixelLayout* aSrcLayout, uint8_t* aDstBuffer,
                      ImageBitmapFormat aDstFormat, int aDstChannelCount,
-                     mozilla::function<int (const uint8_t*, int, const uint8_t*, int, const uint8_t*, int, uint8_t*, int, int, int)> converter)
+                     std::function<int (const uint8_t*, int, const uint8_t*, int, const uint8_t*, int, uint8_t*, int, int, int)> converter)
 {
   MOZ_ASSERT(aSrcUtils, "Convert color from a null utility object.");
   MOZ_ASSERT(aSrcBuffer, "Convert color from a null buffer.");
   MOZ_ASSERT(aSrcLayout, "Convert color from a null layout.");
   MOZ_ASSERT(aDstBuffer, "Convert color to a null buffer.");
 
   const nsTArray<ChannelPixelLayout>& channels = *aSrcLayout;
   MOZ_ASSERT(channels.Length() == aSrcUtils->GetChannelCount(),
@@ -378,17 +379,17 @@ CvtYUVImgToSimpleImg(Utils* aSrcUtils, c
   return CreateDefaultPixelLayout(aDstFormat, channels[0].mWidth,
                                   channels[0].mHeight, dstStride);
 }
 
 static UniquePtr<ImagePixelLayout>
 CvtNVImgToSimpleImg(Utils* aSrcUtils, const uint8_t* aSrcBuffer,
                     const ImagePixelLayout* aSrcLayout, uint8_t* aDstBuffer,
                     ImageBitmapFormat aDstFormat, int aDstChannelCount,
-                    mozilla::function<int (const uint8_t*, int, const uint8_t*, int, uint8_t*, int, int, int)> converter)
+                    std::function<int (const uint8_t*, int, const uint8_t*, int, uint8_t*, int, int, int)> converter)
 {
   MOZ_ASSERT(aSrcUtils, "Convert color from a null utility object.");
   MOZ_ASSERT(aSrcBuffer, "Convert color from a null buffer.");
   MOZ_ASSERT(aSrcLayout, "Convert color from a null layout.");
   MOZ_ASSERT(aDstBuffer, "Convert color to a null buffer.");
 
   const nsTArray<ChannelPixelLayout>& channels = *aSrcLayout;
   MOZ_ASSERT(channels.Length() == aSrcUtils->GetChannelCount(),
@@ -407,17 +408,17 @@ CvtNVImgToSimpleImg(Utils* aSrcUtils, co
   return CreateDefaultPixelLayout(aDstFormat, channels[0].mWidth,
                                   channels[0].mHeight, dstStride);
 }
 
 static UniquePtr<ImagePixelLayout>
 CvtSimpleImgToYUVImg(Utils* aSrcUtils, const uint8_t* aSrcBuffer,
                      const ImagePixelLayout* aSrcLayout, uint8_t* aDstBuffer,
                      ImageBitmapFormat aDstFormat,
-                     mozilla::function<int (const uint8_t*, int, uint8_t*, int, uint8_t*, int, uint8_t*, int, int, int)> converter)
+                     std::function<int (const uint8_t*, int, uint8_t*, int, uint8_t*, int, uint8_t*, int, int, int)> converter)
 {
   MOZ_ASSERT(aSrcUtils, "Convert color from a null utility object.");
   MOZ_ASSERT(aSrcBuffer, "Convert color from a null buffer.");
   MOZ_ASSERT(aSrcLayout, "Convert color from a null layout.");
   MOZ_ASSERT(aDstBuffer, "Convert color to a null buffer.");
 
   UniquePtr<ImagePixelLayout> layout =
     CreateDefaultPixelLayout(aDstFormat, (*aSrcLayout)[0].mWidth,
@@ -439,17 +440,17 @@ CvtSimpleImgToYUVImg(Utils* aSrcUtils, c
 
   return layout;
 }
 
 static UniquePtr<ImagePixelLayout>
 CvtSimpleImgToNVImg(Utils* aSrcUtils, const uint8_t* aSrcBuffer,
                     const ImagePixelLayout* aSrcLayout, uint8_t* aDstBuffer,
                     ImageBitmapFormat aDstFormat,
-                    mozilla::function<int (const uint8_t*, int, uint8_t*, int, uint8_t*, int, int, int)> converter)
+                    std::function<int (const uint8_t*, int, uint8_t*, int, uint8_t*, int, int, int)> converter)
 {
   MOZ_ASSERT(aSrcUtils, "Convert color from a null utility object.");
   MOZ_ASSERT(aSrcBuffer, "Convert color from a null buffer.");
   MOZ_ASSERT(aSrcLayout, "Convert color from a null layout.");
   MOZ_ASSERT(aDstBuffer, "Convert color to a null buffer.");
 
   UniquePtr<ImagePixelLayout> layout =
     CreateDefaultPixelLayout(aDstFormat, (*aSrcLayout)[0].mWidth,
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -268,16 +268,17 @@ class WebGLContext
     , public WebGLRectangleObject
     , public nsWrapperCache
 {
     friend class ScopedDrawHelper;
     friend class ScopedDrawWithTransformFeedback;
     friend class ScopedFBRebinder;
     friend class WebGL2Context;
     friend class WebGLContextUserData;
+    friend class WebGLExtensionCompressedTextureASTC;
     friend class WebGLExtensionCompressedTextureATC;
     friend class WebGLExtensionCompressedTextureES3;
     friend class WebGLExtensionCompressedTextureETC1;
     friend class WebGLExtensionCompressedTexturePVRTC;
     friend class WebGLExtensionCompressedTextureS3TC;
     friend class WebGLExtensionDepthTexture;
     friend class WebGLExtensionDisjointTimerQuery;
     friend class WebGLExtensionDrawBuffers;
--- a/dom/canvas/WebGLContextExtensions.cpp
+++ b/dom/canvas/WebGLContextExtensions.cpp
@@ -43,16 +43,17 @@ WebGLContext::GetExtensionString(WebGLEx
         WEBGL_EXTENSION_IDENTIFIER(OES_element_index_uint)
         WEBGL_EXTENSION_IDENTIFIER(OES_standard_derivatives)
         WEBGL_EXTENSION_IDENTIFIER(OES_texture_float)
         WEBGL_EXTENSION_IDENTIFIER(OES_texture_float_linear)
         WEBGL_EXTENSION_IDENTIFIER(OES_texture_half_float)
         WEBGL_EXTENSION_IDENTIFIER(OES_texture_half_float_linear)
         WEBGL_EXTENSION_IDENTIFIER(OES_vertex_array_object)
         WEBGL_EXTENSION_IDENTIFIER(WEBGL_color_buffer_float)
+        WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_astc)
         WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_atc)
         WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_etc)
         WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_etc1)
         WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_pvrtc)
         WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_s3tc)
         WEBGL_EXTENSION_IDENTIFIER(WEBGL_debug_renderer_info)
         WEBGL_EXTENSION_IDENTIFIER(WEBGL_debug_shaders)
         WEBGL_EXTENSION_IDENTIFIER(WEBGL_depth_texture)
@@ -117,16 +118,18 @@ WebGLContext::IsExtensionSupported(WebGL
     case WebGLExtensionID::EXT_texture_filter_anisotropic:
         return gl->IsExtensionSupported(gl::GLContext::EXT_texture_filter_anisotropic);
 
     // OES_
     case WebGLExtensionID::OES_texture_float_linear:
         return gl->IsSupported(gl::GLFeature::texture_float_linear);
 
     // WEBGL_
+    case WebGLExtensionID::WEBGL_compressed_texture_astc:
+        return WebGLExtensionCompressedTextureASTC::IsSupported(this);
     case WebGLExtensionID::WEBGL_compressed_texture_atc:
         return gl->IsExtensionSupported(gl::GLContext::AMD_compressed_ATC_texture);
     case WebGLExtensionID::WEBGL_compressed_texture_etc:
         return gl->IsSupported(gl::GLFeature::ES3_compatibility);
     case WebGLExtensionID::WEBGL_compressed_texture_etc1:
         return gl->IsExtensionSupported(gl::GLContext::OES_compressed_ETC1_RGB8_texture);
     case WebGLExtensionID::WEBGL_compressed_texture_pvrtc:
         return gl->IsExtensionSupported(gl::GLContext::IMG_texture_compression_pvrtc);
@@ -394,16 +397,19 @@ WebGLContext::EnableExtension(WebGLExten
     case WebGLExtensionID::OES_vertex_array_object:
         obj = new WebGLExtensionVertexArray(this);
         break;
 
     // WEBGL_
     case WebGLExtensionID::WEBGL_color_buffer_float:
         obj = new WebGLExtensionColorBufferFloat(this);
         break;
+    case WebGLExtensionID::WEBGL_compressed_texture_astc:
+        obj = new WebGLExtensionCompressedTextureASTC(this);
+        break;
     case WebGLExtensionID::WEBGL_compressed_texture_atc:
         obj = new WebGLExtensionCompressedTextureATC(this);
         break;
     case WebGLExtensionID::WEBGL_compressed_texture_etc:
         obj = new WebGLExtensionCompressedTextureES3(this);
         break;
     case WebGLExtensionID::WEBGL_compressed_texture_etc1:
         obj = new WebGLExtensionCompressedTextureETC1(this);
new file mode 100644
--- /dev/null
+++ b/dom/canvas/WebGLExtensionCompressedTextureASTC.cpp
@@ -0,0 +1,95 @@
+/* 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 "WebGLExtensions.h"
+
+#include "GLContext.h"
+#include "mozilla/dom/WebGLRenderingContextBinding.h"
+#include "WebGLContext.h"
+
+namespace mozilla {
+
+WebGLExtensionCompressedTextureASTC::WebGLExtensionCompressedTextureASTC(WebGLContext* webgl)
+    : WebGLExtensionBase(webgl)
+{
+    MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
+
+    RefPtr<WebGLContext> webgl_ = webgl; // Bug 1201275
+    const auto fnAdd = [&webgl_](GLenum sizedFormat, webgl::EffectiveFormat effFormat) {
+        auto& fua = webgl_->mFormatUsage;
+
+        auto usage = fua->EditUsage(effFormat);
+        usage->isFilterable = true;
+        fua->AllowSizedTexFormat(sizedFormat, usage);
+
+        webgl_->mCompressedTextureFormats.AppendElement(sizedFormat);
+    };
+
+#define FOO(x) LOCAL_GL_ ## x, webgl::EffectiveFormat::x
+
+    fnAdd(FOO(COMPRESSED_RGBA_ASTC_4x4_KHR));
+    fnAdd(FOO(COMPRESSED_RGBA_ASTC_5x4_KHR));
+    fnAdd(FOO(COMPRESSED_RGBA_ASTC_5x5_KHR));
+    fnAdd(FOO(COMPRESSED_RGBA_ASTC_6x5_KHR));
+    fnAdd(FOO(COMPRESSED_RGBA_ASTC_6x6_KHR));
+    fnAdd(FOO(COMPRESSED_RGBA_ASTC_8x5_KHR));
+    fnAdd(FOO(COMPRESSED_RGBA_ASTC_8x6_KHR));
+    fnAdd(FOO(COMPRESSED_RGBA_ASTC_8x8_KHR));
+    fnAdd(FOO(COMPRESSED_RGBA_ASTC_10x5_KHR));
+    fnAdd(FOO(COMPRESSED_RGBA_ASTC_10x6_KHR));
+    fnAdd(FOO(COMPRESSED_RGBA_ASTC_10x8_KHR));
+    fnAdd(FOO(COMPRESSED_RGBA_ASTC_10x10_KHR));
+    fnAdd(FOO(COMPRESSED_RGBA_ASTC_12x10_KHR));
+    fnAdd(FOO(COMPRESSED_RGBA_ASTC_12x12_KHR));
+
+    fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR));
+    fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR));
+    fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR));
+    fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR));
+    fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR));
+    fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR));
+    fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR));
+    fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR));
+    fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR));
+    fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR));
+    fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR));
+    fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR));
+    fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR));
+    fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR));
+
+#undef FOO
+}
+
+WebGLExtensionCompressedTextureASTC::~WebGLExtensionCompressedTextureASTC()
+{
+}
+
+void
+WebGLExtensionCompressedTextureASTC::GetSupportedProfiles(dom::Nullable< nsTArray<nsString> >& retval) const
+{
+    retval.SetNull();
+    if (mIsLost) {
+        mContext->ErrorInvalidOperation("%s: Extension is lost.",
+                                        "drawElementsInstancedANGLE");
+        return;
+    }
+
+    nsTArray<nsString>& arr = retval.SetValue();
+    arr.AppendElement(NS_LITERAL_STRING("ldr"));
+
+    if (mContext->gl->IsExtensionSupported(gl::GLContext::KHR_texture_compression_astc_hdr)) {
+        arr.AppendElement(NS_LITERAL_STRING("hdr"));
+    }
+}
+
+bool
+WebGLExtensionCompressedTextureASTC::IsSupported(const WebGLContext* webgl)
+{
+    gl::GLContext* gl = webgl->GL();
+    return gl->IsExtensionSupported(gl::GLContext::KHR_texture_compression_astc_ldr);
+}
+
+IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionCompressedTextureASTC, WEBGL_compressed_texture_astc)
+
+} // namespace mozilla
--- a/dom/canvas/WebGLExtensions.h
+++ b/dom/canvas/WebGLExtensions.h
@@ -2,25 +2,27 @@
 /* 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/. */
 
 #ifndef WEBGL_EXTENSIONS_H_
 #define WEBGL_EXTENSIONS_H_
 
 #include "mozilla/AlreadyAddRefed.h"
+#include "nsString.h"
+#include "nsTArray.h"
 #include "nsWrapperCache.h"
 #include "WebGLObjectModel.h"
 #include "WebGLTypes.h"
 
 namespace mozilla {
 
 namespace dom {
-template<typename T>
-class Sequence;
+template<typename> struct Nullable;
+template<typename> class Sequence;
 } // namespace dom
 
 namespace webgl {
 class FormatUsageAuthority;
 } // namespace webgl
 
 class WebGLContext;
 class WebGLShader;
@@ -55,16 +57,32 @@ protected:
     virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
 
 #define IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionType, WebGLBindingType)\
     JSObject*                                                    \
     WebGLExtensionType::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) {              \
         return dom::WebGLBindingType##Binding::Wrap(cx, this, givenProto); \
     }
 
+////
+
+class WebGLExtensionCompressedTextureASTC
+    : public WebGLExtensionBase
+{
+public:
+    explicit WebGLExtensionCompressedTextureASTC(WebGLContext* webgl);
+    virtual ~WebGLExtensionCompressedTextureASTC();
+
+    void GetSupportedProfiles(dom::Nullable< nsTArray<nsString> >& retval) const;
+
+    static bool IsSupported(const WebGLContext* webgl);
+
+    DECL_WEBGL_EXTENSION_GOOP
+};
+
 class WebGLExtensionCompressedTextureATC
     : public WebGLExtensionBase
 {
 public:
     explicit WebGLExtensionCompressedTextureATC(WebGLContext*);
     virtual ~WebGLExtensionCompressedTextureATC();
 
     DECL_WEBGL_EXTENSION_GOOP
--- a/dom/canvas/WebGLFormats.cpp
+++ b/dom/canvas/WebGLFormats.cpp
@@ -108,16 +108,47 @@ InitCompressedFormatInfo()
     AddCompressedFormatInfo(EffectiveFormat::ATC_RGBA_INTERPOLATED_ALPHA_AMD, 128, 4, 4, CompressionFamily::ATC);
 
     // EXT_texture_compression_s3tc
     AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGB_S3TC_DXT1_EXT ,  64, 4, 4, CompressionFamily::S3TC);
     AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_S3TC_DXT1_EXT,  64, 4, 4, CompressionFamily::S3TC);
     AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_S3TC_DXT3_EXT, 128, 4, 4, CompressionFamily::S3TC);
     AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_S3TC_DXT5_EXT, 128, 4, 4, CompressionFamily::S3TC);
 
+    // KHR_texture_compression_astc_ldr
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_4x4_KHR          , 128,  4,  4, CompressionFamily::ASTC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_5x4_KHR          , 128,  5,  4, CompressionFamily::ASTC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_5x5_KHR          , 128,  5,  5, CompressionFamily::ASTC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_6x5_KHR          , 128,  6,  5, CompressionFamily::ASTC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_6x6_KHR          , 128,  6,  6, CompressionFamily::ASTC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_8x5_KHR          , 128,  8,  5, CompressionFamily::ASTC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_8x6_KHR          , 128,  8,  6, CompressionFamily::ASTC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_8x8_KHR          , 128,  8,  8, CompressionFamily::ASTC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_10x5_KHR         , 128, 10,  5, CompressionFamily::ASTC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_10x6_KHR         , 128, 10,  6, CompressionFamily::ASTC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_10x8_KHR         , 128, 10,  8, CompressionFamily::ASTC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_10x10_KHR        , 128, 10, 10, CompressionFamily::ASTC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_12x10_KHR        , 128, 12, 10, CompressionFamily::ASTC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_12x12_KHR        , 128, 12, 12, CompressionFamily::ASTC);
+
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR  , 128,  4,  4, CompressionFamily::ASTC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR  , 128,  5,  4, CompressionFamily::ASTC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR  , 128,  5,  5, CompressionFamily::ASTC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR  , 128,  6,  5, CompressionFamily::ASTC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR  , 128,  6,  6, CompressionFamily::ASTC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR  , 128,  8,  5, CompressionFamily::ASTC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR  , 128,  8,  6, CompressionFamily::ASTC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR  , 128,  8,  8, CompressionFamily::ASTC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR , 128, 10,  5, CompressionFamily::ASTC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR , 128, 10,  6, CompressionFamily::ASTC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR , 128, 10,  8, CompressionFamily::ASTC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, 128, 10, 10, CompressionFamily::ASTC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, 128, 12, 10, CompressionFamily::ASTC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, 128, 12, 12, CompressionFamily::ASTC);
+
     // IMG_texture_compression_pvrtc
     AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGB_PVRTC_4BPPV1 , 256,  8, 8, CompressionFamily::PVRTC);
     AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_PVRTC_4BPPV1, 256,  8, 8, CompressionFamily::PVRTC);
     AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGB_PVRTC_2BPPV1 , 256, 16, 8, CompressionFamily::PVRTC);
     AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_PVRTC_2BPPV1, 256, 16, 8, CompressionFamily::PVRTC);
 
     // OES_compressed_ETC1_RGB8_texture
     AddCompressedFormatInfo(EffectiveFormat::ETC1_RGB8_OES, 64, 4, 4, CompressionFamily::ETC1);
@@ -287,16 +318,47 @@ InitFormatInfo()
     AddFormatInfo(FOO(ATC_RGBA_INTERPOLATED_ALPHA_AMD), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
 
     // EXT_texture_compression_s3tc
     AddFormatInfo(FOO(COMPRESSED_RGB_S3TC_DXT1_EXT ), 0, 1,1,1,0, 0,0, UnsizedFormat::RGB , false, ComponentType::NormUInt);
     AddFormatInfo(FOO(COMPRESSED_RGBA_S3TC_DXT1_EXT), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
     AddFormatInfo(FOO(COMPRESSED_RGBA_S3TC_DXT3_EXT), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
     AddFormatInfo(FOO(COMPRESSED_RGBA_S3TC_DXT5_EXT), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
 
+    // KHR_texture_compression_astc_ldr
+    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_4x4_KHR          ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_5x4_KHR          ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_5x5_KHR          ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_6x5_KHR          ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_6x6_KHR          ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_8x5_KHR          ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_8x6_KHR          ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_8x8_KHR          ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_10x5_KHR         ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_10x6_KHR         ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_10x8_KHR         ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_10x10_KHR        ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_12x10_KHR        ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_12x12_KHR        ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
+
+    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR  ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR  ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR  ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR  ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR  ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR  ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR  ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR  ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
+
     // IMG_texture_compression_pvrtc
     AddFormatInfo(FOO(COMPRESSED_RGB_PVRTC_4BPPV1 ), 0, 1,1,1,0, 0,0, UnsizedFormat::RGB , false, ComponentType::NormUInt);
     AddFormatInfo(FOO(COMPRESSED_RGBA_PVRTC_4BPPV1), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
     AddFormatInfo(FOO(COMPRESSED_RGB_PVRTC_2BPPV1 ), 0, 1,1,1,0, 0,0, UnsizedFormat::RGB , false, ComponentType::NormUInt);
     AddFormatInfo(FOO(COMPRESSED_RGBA_PVRTC_2BPPV1), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
 
     // OES_compressed_ETC1_RGB8_texture
     AddFormatInfo(FOO(ETC1_RGB8_OES), 0, 1,1,1,0, 0,0, UnsizedFormat::RGB, false, ComponentType::NormUInt);
--- a/dom/canvas/WebGLFormats.h
+++ b/dom/canvas/WebGLFormats.h
@@ -114,16 +114,47 @@ enum class EffectiveFormat : EffectiveFo
     ATC_RGBA_INTERPOLATED_ALPHA_AMD,
 
     // EXT_texture_compression_s3tc
     COMPRESSED_RGB_S3TC_DXT1_EXT,
     COMPRESSED_RGBA_S3TC_DXT1_EXT,
     COMPRESSED_RGBA_S3TC_DXT3_EXT,
     COMPRESSED_RGBA_S3TC_DXT5_EXT,
 
+    // KHR_texture_compression_astc_ldr
+    COMPRESSED_RGBA_ASTC_4x4_KHR,
+    COMPRESSED_RGBA_ASTC_5x4_KHR,
+    COMPRESSED_RGBA_ASTC_5x5_KHR,
+    COMPRESSED_RGBA_ASTC_6x5_KHR,
+    COMPRESSED_RGBA_ASTC_6x6_KHR,
+    COMPRESSED_RGBA_ASTC_8x5_KHR,
+    COMPRESSED_RGBA_ASTC_8x6_KHR,
+    COMPRESSED_RGBA_ASTC_8x8_KHR,
+    COMPRESSED_RGBA_ASTC_10x5_KHR,
+    COMPRESSED_RGBA_ASTC_10x6_KHR,
+    COMPRESSED_RGBA_ASTC_10x8_KHR,
+    COMPRESSED_RGBA_ASTC_10x10_KHR,
+    COMPRESSED_RGBA_ASTC_12x10_KHR,
+    COMPRESSED_RGBA_ASTC_12x12_KHR,
+
+    COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR,
+    COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR,
+    COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR,
+    COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR,
+    COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR,
+    COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR,
+    COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR,
+    COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR,
+    COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR,
+    COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR,
+    COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR,
+    COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR,
+    COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR,
+    COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR,
+
     // IMG_texture_compression_pvrtc
     COMPRESSED_RGB_PVRTC_4BPPV1,
     COMPRESSED_RGBA_PVRTC_4BPPV1,
     COMPRESSED_RGB_PVRTC_2BPPV1,
     COMPRESSED_RGBA_PVRTC_2BPPV1,
 
     // OES_compressed_ETC1_RGB8_texture
     ETC1_RGB8_OES,
@@ -168,21 +199,22 @@ enum class ComponentType : uint8_t {
     UInt,         // RGBA32UI, STENCIL_INDEX8
     NormInt,      // RGBA8_SNORM
     NormUInt,     // RGBA8, DEPTH_COMPONENT16
     Float,        // RGBA32F
     Special,      // DEPTH24_STENCIL8
 };
 
 enum class CompressionFamily : uint8_t {
-    ETC1,
-    ES3, // ETC2 or EAC
+    ASTC,
     ATC,
+    ES3, // ETC2 or EAC
+    ETC1,
+    PVRTC,
     S3TC,
-    PVRTC,
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 
 struct CompressedFormatInfo
 {
     const EffectiveFormat effectiveFormat;
     const uint8_t bytesPerBlock;
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -926,16 +926,26 @@ ValidateCompressedTexImageRestrictions(c
 
         if (level == 0)
             return false;
 
         return (size == 0 || size == 1 || size == 2);
     };
 
     switch (format->compression->family) {
+    case webgl::CompressionFamily::ASTC:
+        if (target == LOCAL_GL_TEXTURE_3D &&
+            !webgl->gl->IsExtensionSupported(gl::GLContext::KHR_texture_compression_astc_hdr))
+        {
+            webgl->ErrorInvalidOperation("%s: TEXTURE_3D requires ASTC's hdr profile.",
+                                         funcName);
+            return false;
+        }
+        break;
+
     case webgl::CompressionFamily::PVRTC:
         if (!IsPowerOfTwo(width) || !IsPowerOfTwo(height)) {
             webgl->ErrorInvalidValue("%s: %s requires power-of-two width and height.",
                                      funcName, format->name);
             return false;
         }
 
         break;
--- a/dom/canvas/WebGLTypes.h
+++ b/dom/canvas/WebGLTypes.h
@@ -152,16 +152,17 @@ enum class WebGLExtensionID : uint8_t {
     OES_element_index_uint,
     OES_standard_derivatives,
     OES_texture_float,
     OES_texture_float_linear,
     OES_texture_half_float,
     OES_texture_half_float_linear,
     OES_vertex_array_object,
     WEBGL_color_buffer_float,
+    WEBGL_compressed_texture_astc,
     WEBGL_compressed_texture_atc,
     WEBGL_compressed_texture_etc,
     WEBGL_compressed_texture_etc1,
     WEBGL_compressed_texture_pvrtc,
     WEBGL_compressed_texture_s3tc,
     WEBGL_debug_renderer_info,
     WEBGL_debug_shaders,
     WEBGL_depth_texture,
--- a/dom/canvas/moz.build
+++ b/dom/canvas/moz.build
@@ -103,16 +103,17 @@ UNIFIED_SOURCES += [
     'WebGLContextValidate.cpp',
     'WebGLContextVertexArray.cpp',
     'WebGLContextVertices.cpp',
     'WebGLElementArrayCache.cpp',
     'WebGLExtensionBase.cpp',
     'WebGLExtensionBlendMinMax.cpp',
     'WebGLExtensionColorBufferFloat.cpp',
     'WebGLExtensionColorBufferHalfFloat.cpp',
+    'WebGLExtensionCompressedTextureASTC.cpp',
     'WebGLExtensionCompressedTextureATC.cpp',
     'WebGLExtensionCompressedTextureES3.cpp',
     'WebGLExtensionCompressedTextureETC1.cpp',
     'WebGLExtensionCompressedTexturePVRTC.cpp',
     'WebGLExtensionCompressedTextureS3TC.cpp',
     'WebGLExtensionDebugRendererInfo.cpp',
     'WebGLExtensionDebugShaders.cpp',
     'WebGLExtensionDepthTexture.cpp',
--- a/dom/fetch/Fetch.cpp
+++ b/dom/fetch/Fetch.cpp
@@ -523,17 +523,19 @@ ExtractFromBlob(const Blob& aBlob,
 
   impl->GetInternalStream(aStream, rv);
   if (NS_WARN_IF(rv.Failed())) {
     return rv.StealNSResult();
   }
 
   nsAutoString type;
   impl->GetType(type);
-  aContentType = NS_ConvertUTF16toUTF8(type);
+  if (!type.IsEmpty()) {
+    CopyUTF16toUTF8(type, aContentType);
+  }
   return NS_OK;
 }
 
 nsresult
 ExtractFromFormData(FormData& aFormData,
                     nsIInputStream** aStream,
                     nsCString& aContentType,
                     uint64_t& aContentLength)
@@ -598,16 +600,17 @@ ExtractFromURLSearchParams(const URLSear
 
 nsresult
 ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& aBodyInit,
                           nsIInputStream** aStream,
                           nsCString& aContentType,
                           uint64_t& aContentLength)
 {
   MOZ_ASSERT(aStream);
+  aContentType.SetIsVoid(true);
 
   if (aBodyInit.IsArrayBuffer()) {
     const ArrayBuffer& buf = aBodyInit.GetAsArrayBuffer();
     return ExtractFromArrayBuffer(buf, aStream, aContentLength);
   }
   if (aBodyInit.IsArrayBufferView()) {
     const ArrayBufferView& buf = aBodyInit.GetAsArrayBufferView();
     return ExtractFromArrayBufferView(buf, aStream, aContentLength);
@@ -637,16 +640,17 @@ ExtractByteStreamFromBody(const OwningAr
 nsresult
 ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& aBodyInit,
                           nsIInputStream** aStream,
                           nsCString& aContentType,
                           uint64_t& aContentLength)
 {
   MOZ_ASSERT(aStream);
   MOZ_ASSERT(!*aStream);
+  aContentType.SetIsVoid(true);
 
   if (aBodyInit.IsArrayBuffer()) {
     const ArrayBuffer& buf = aBodyInit.GetAsArrayBuffer();
     return ExtractFromArrayBuffer(buf, aStream, aContentLength);
   }
   if (aBodyInit.IsArrayBufferView()) {
     const ArrayBufferView& buf = aBodyInit.GetAsArrayBufferView();
     return ExtractFromArrayBufferView(buf, aStream, aContentLength);
--- a/dom/jsurl/nsJSProtocolHandler.cpp
+++ b/dom/jsurl/nsJSProtocolHandler.cpp
@@ -178,17 +178,17 @@ nsresult nsJSThunk::EvaluateScript(nsICh
     // allowed.
     nsCOMPtr<nsIContentSecurityPolicy> csp;
     rv = principal->GetCsp(getter_AddRefs(csp));
     NS_ENSURE_SUCCESS(rv, rv);
     if (csp) {
         bool allowsInlineScript = true;
         rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
                                   EmptyString(), // aNonce
-                                  false,         // aParserCreated
+                                  true,         // aParserCreated
                                   EmptyString(), // aContent
                                   0,             // aLineNumber
                                   &allowsInlineScript);
 
         //return early if inline scripts are not allowed
         if (!allowsInlineScript) {
           return NS_ERROR_DOM_RETVAL_UNDEFINED;
         }
--- a/dom/locales/en-US/chrome/plugins.properties
+++ b/dom/locales/en-US/chrome/plugins.properties
@@ -16,16 +16,19 @@ version_label=Version:
 state_label=State:
 state_enabled=Enabled
 state_disabled=Disabled
 mimetype_label=MIME Type
 description_label=Description
 suffixes_label=Suffixes
 learn_more_label=Learn More
 
+deprecation_description=Missing something? Some plugins are no longer supported.
+deprecation_learn_more=Learn More.
+
 # GMP Plugins
 gmp_license_info=License information
 gmp_privacy_info=Privacy Information
 
 openH264_name=OpenH264 Video Codec provided by Cisco Systems, Inc.
 openH264_description2=This plugin is automatically installed by Mozilla to comply with the WebRTC specification and to enable WebRTC calls with devices that require the H.264 video codec. Visit http://www.openh264.org/ to view the codec source code and learn more about the implementation.
 
 eme-adobe_name=Primetime Content Decryption Module provided by Adobe Systems, Incorporated
--- a/dom/media/VideoUtils.cpp
+++ b/dom/media/VideoUtils.cpp
@@ -2,17 +2,16 @@
  * 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 "VideoUtils.h"
 
 #include "mozilla/Base64.h"
 #include "mozilla/TaskQueue.h"
 #include "mozilla/Telemetry.h"
-#include "mozilla/Function.h"
 
 #include "MediaContentType.h"
 #include "MediaPrefs.h"
 #include "MediaResource.h"
 #include "TimeUnits.h"
 #include "nsMathUtils.h"
 #include "nsSize.h"
 #include "VorbisUtils.h"
@@ -21,16 +20,17 @@
 #include "nsIRandomGenerator.h"
 #include "nsIServiceManager.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIConsoleService.h"
 #include "nsThreadUtils.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsContentTypeParser.h"
 
+#include <functional>
 #include <stdint.h>
 
 namespace mozilla {
 
 NS_NAMED_LITERAL_CSTRING(kEMEKeySystemClearkey, "org.w3.clearkey");
 NS_NAMED_LITERAL_CSTRING(kEMEKeySystemWidevine, "com.widevine.alpha");
 NS_NAMED_LITERAL_CSTRING(kEMEKeySystemPrimetime, "com.adobe.primetime");
 
--- a/dom/media/platforms/PDMFactory.cpp
+++ b/dom/media/platforms/PDMFactory.cpp
@@ -47,16 +47,18 @@
 #include "mozilla/dom/RemoteVideoDecoder.h"
 
 #ifdef XP_WIN
 #include "mozilla/WindowsVersion.h"
 #endif
 
 #include "mp4_demuxer/H264.h"
 
+#include <functional>
+
 namespace mozilla {
 
 extern already_AddRefed<PlatformDecoderModule> CreateAgnosticDecoderModule();
 extern already_AddRefed<PlatformDecoderModule> CreateBlankDecoderModule();
 
 class PDMFactoryImpl final {
 public:
   PDMFactoryImpl()
@@ -150,17 +152,17 @@ public:
       }
     }
     return CheckResult(SupportChecker::Reason::kSupported);
   }
 
   void Clear() { mCheckerList.Clear(); }
 
 private:
-  nsTArray<mozilla::function<CheckResult()>> mCheckerList;
+  nsTArray<std::function<CheckResult()>> mCheckerList;
 }; // SupportChecker
 
 PDMFactory::PDMFactory()
 {
   EnsureInit();
   CreatePDMs();
   CreateBlankPDM();
 }
--- a/dom/media/platforms/PDMFactory.h
+++ b/dom/media/platforms/PDMFactory.h
@@ -3,17 +3,16 @@
 /* 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/. */
 
 #if !defined(PDMFactory_h_)
 #define PDMFactory_h_
 
 #include "PlatformDecoderModule.h"
-#include "mozilla/Function.h"
 #include "mozilla/StaticMutex.h"
 
 class CDMProxy;
 
 namespace mozilla {
 
 class DecoderDoctorDiagnostics;
 class PDMFactoryImpl;
--- a/dom/presentation/PresentationSessionInfo.cpp
+++ b/dom/presentation/PresentationSessionInfo.cpp
@@ -2,17 +2,16 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/HTMLIFrameElementBinding.h"
 #include "mozilla/dom/TabParent.h"
-#include "mozilla/Function.h"
 #include "mozilla/Logging.h"
 #include "mozilla/Move.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "nsContentUtils.h"
 #include "nsGlobalWindow.h"
 #include "nsIDocShell.h"
 #include "nsFrameLoader.h"
--- a/dom/quota/QuotaManagerService.cpp
+++ b/dom/quota/QuotaManagerService.cpp
@@ -436,17 +436,21 @@ QuotaManagerService::PerformIdleMaintena
   BatteryInformation batteryInfo;
 
 #ifdef MOZ_WIDGET_ANDROID
   // Android XPCShell doesn't load the AndroidBridge that is needed to make
   // GetCurrentBatteryInformation work...
   if (!QuotaManager::kRunningXPCShellTests)
 #endif
   {
+    // In order to give the correct battery level, hal must have registered
+    // battery observers.
+    RegisterBatteryObserver(this);
     GetCurrentBatteryInformation(&batteryInfo);
+    UnregisterBatteryObserver(this);
   }
 
   // If we're running XPCShell because we always want to be able to test this
   // code so pretend that we're always charging.
   if (QuotaManager::kRunningXPCShellTests) {
     batteryInfo.level() = 100;
     batteryInfo.charging() = true;
   }
@@ -702,16 +706,23 @@ QuotaManagerService::Observe(nsISupports
 
     return NS_OK;
   }
 
   MOZ_ASSERT_UNREACHABLE("Should never get here!");
   return NS_OK;
 }
 
+void
+QuotaManagerService::Notify(const hal::BatteryInformation& aBatteryInfo)
+{
+  // This notification is received when battery data changes. We don't need to
+  // deal with this notification.
+}
+
 NS_IMETHODIMP
 AbortOperationsRunnable::Run()
 {
   AssertIsOnBackgroundThread();
 
   if (QuotaManager::IsShuttingDown()) {
     return NS_OK;
   }
--- a/dom/quota/QuotaManagerService.h
+++ b/dom/quota/QuotaManagerService.h
@@ -3,39 +3,46 @@
 /* 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/. */
 
 #ifndef mozilla_dom_quota_QuotaManagerService_h
 #define mozilla_dom_quota_QuotaManagerService_h
 
 #include "mozilla/dom/ipc/IdType.h"
+#include "mozilla/dom/battery/Types.h"
+#include "mozilla/Observer.h"
 #include "nsAutoPtr.h"
 #include "nsIObserver.h"
 #include "nsIQuotaManagerService.h"
 
 #define QUOTAMANAGER_SERVICE_CONTRACTID \
   "@mozilla.org/dom/quota-manager-service;1"
 
 namespace mozilla {
 namespace ipc {
 
 class PBackgroundChild;
 
 } // namespace ipc
 
+namespace hal {
+class BatteryInformation;
+}
+
 namespace dom {
 namespace quota {
 
 class QuotaChild;
 class QuotaManager;
 
 class QuotaManagerService final
   : public nsIQuotaManagerService
   , public nsIObserver
+  , public BatteryObserver
 {
   typedef mozilla::ipc::PBackgroundChild PBackgroundChild;
 
   class BackgroundCreateCallback;
   class PendingRequestInfo;
   class UsageRequestInfo;
   class RequestInfo;
   class IdleMaintenanceInfo;
@@ -99,15 +106,19 @@ private:
   PerformIdleMaintenance();
 
   void
   RemoveIdleObserver();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIQUOTAMANAGERSERVICE
   NS_DECL_NSIOBSERVER
+
+  // BatteryObserver override
+  void
+  Notify(const hal::BatteryInformation& aBatteryInfo) override;
 };
 
 } // namespace quota
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_quota_QuotaManagerService_h */
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/file_strict_dynamic_js_url.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Bug 1316826 - 'strict-dynamic' blocking DOM event handlers</title>
+</head>
+<body>
+<div id="testdiv">blocked</div>
+
+<a id="jslink" href='javascript:document.getElementById("testdiv").innerHTML = "allowed"'>click me</a>
+<script nonce="foo">
+  document.getElementById("jslink").click();
+</script>
+
+</body>
+</html>
--- a/dom/security/test/csp/mochitest.ini
+++ b/dom/security/test/csp/mochitest.ini
@@ -184,16 +184,17 @@ support-files =
   file_sandbox_11.html
   file_sandbox_12.html
   file_require_sri_meta.sjs
   file_require_sri_meta.js
   file_sendbeacon.html
   file_upgrade_insecure_docwrite_iframe.sjs
   file_data-uri_blocked.html
   file_data-uri_blocked.html^headers^
+  file_strict_dynamic_js_url.html
   file_strict_dynamic_script_events.html
   file_strict_dynamic_script_events_xbl.html
   file_strict_dynamic_script_inline.html
   file_strict_dynamic_script_extern.html
   file_strict_dynamic.js
   file_strict_dynamic_parser_inserted_doc_write.html
   file_strict_dynamic_parser_inserted_doc_write_correct_nonce.html
   file_strict_dynamic_non_parser_inserted.html
--- a/dom/security/test/csp/test_strict_dynamic.html
+++ b/dom/security/test/csp/test_strict_dynamic.html
@@ -79,17 +79,23 @@ var tests = [
     policy: "script-src 'strict-dynamic' 'nonce-foo'"
   },
   {
     // marquee is a special snowflake. Extra test for xbl things.
     desc: "strict-dynamic with DOM events should be blocked (XBL)",
     result: "blocked",
     file: "file_strict_dynamic_script_events_xbl.html",
     policy: "script-src 'strict-dynamic' 'nonce-foo'"
-  }
+  },
+  {
+    desc: "strict-dynamic with JS URLs should be blocked",
+    result: "blocked",
+    file: "file_strict_dynamic_js_url.html",
+    policy: "script-src 'strict-dynamic' 'nonce-foo'"
+  },
 ];
 
 var counter = 0;
 var curTest;
 
 function loadNextTest() {
   if (counter == tests.length) {
     SimpleTest.finish();
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -610,19 +610,19 @@ var interfaceNamesInGlobalScope =
     {name: "ImageCaptureErrorEvent", disabled: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "ImageData",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "InputEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "InstallTrigger",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    "IntersectionObserver",
+    {name: "IntersectionObserver", disabled: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    "IntersectionObserverEntry",
+    {name: "IntersectionObserverEntry", disabled: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "KeyEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "KeyboardEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "KeyframeEffectReadOnly", release: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "KeyframeEffect", release: false},
--- a/dom/webidl/IntersectionObserver.webidl
+++ b/dom/webidl/IntersectionObserver.webidl
@@ -2,34 +2,35 @@
 /* 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/.
  *
  * The origin of this IDL file is
  * https://wicg.github.io/IntersectionObserver/
  */
 
-[ProbablyShortLivingObject]
+[ProbablyShortLivingObject, Pref="dom.IntersectionObserver.enabled"]
 interface IntersectionObserverEntry {
   [Constant]
   readonly attribute DOMHighResTimeStamp time;
   [Constant]
   readonly attribute DOMRectReadOnly? rootBounds;
   [Constant]
   readonly attribute DOMRectReadOnly boundingClientRect;
   [Constant]
   readonly attribute DOMRectReadOnly intersectionRect;
   [Constant]
   readonly attribute double intersectionRatio;
   [Constant]
   readonly attribute Element target;
 };
 
 [Constructor(IntersectionCallback intersectionCallback,
-             optional IntersectionObserverInit options)]
+             optional IntersectionObserverInit options),
+ Pref="dom.IntersectionObserver.enabled"]
 interface IntersectionObserver {
   [Constant]
   readonly attribute Element? root;
   [Constant]
   readonly attribute DOMString rootMargin;
   [Constant,Cached]
   readonly attribute sequence<double> thresholds;
   void observe(Element target);
--- a/dom/webidl/WebGLRenderingContext.webidl
+++ b/dom/webidl/WebGLRenderingContext.webidl
@@ -792,16 +792,53 @@ interface WEBGL_compressed_texture_s3tc
 {
     const GLenum COMPRESSED_RGB_S3TC_DXT1_EXT  = 0x83F0;
     const GLenum COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1;
     const GLenum COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2;
     const GLenum COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3;
 };
 
 [NoInterfaceObject]
+interface WEBGL_compressed_texture_astc {
+    /* Compressed Texture Format */
+    const GLenum COMPRESSED_RGBA_ASTC_4x4_KHR = 0x93B0;
+    const GLenum COMPRESSED_RGBA_ASTC_5x4_KHR = 0x93B1;
+    const GLenum COMPRESSED_RGBA_ASTC_5x5_KHR = 0x93B2;
+    const GLenum COMPRESSED_RGBA_ASTC_6x5_KHR = 0x93B3;
+    const GLenum COMPRESSED_RGBA_ASTC_6x6_KHR = 0x93B4;
+    const GLenum COMPRESSED_RGBA_ASTC_8x5_KHR = 0x93B5;
+    const GLenum COMPRESSED_RGBA_ASTC_8x6_KHR = 0x93B6;
+    const GLenum COMPRESSED_RGBA_ASTC_8x8_KHR = 0x93B7;
+    const GLenum COMPRESSED_RGBA_ASTC_10x5_KHR = 0x93B8;
+    const GLenum COMPRESSED_RGBA_ASTC_10x6_KHR = 0x93B9;
+    const GLenum COMPRESSED_RGBA_ASTC_10x8_KHR = 0x93BA;
+    const GLenum COMPRESSED_RGBA_ASTC_10x10_KHR = 0x93BB;
+    const GLenum COMPRESSED_RGBA_ASTC_12x10_KHR = 0x93BC;
+    const GLenum COMPRESSED_RGBA_ASTC_12x12_KHR = 0x93BD;
+
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR = 0x93D0;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR = 0x93D1;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR = 0x93D2;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR = 0x93D3;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR = 0x93D4;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR = 0x93D5;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR = 0x93D6;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR = 0x93D7;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR = 0x93D8;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR = 0x93D9;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR = 0x93DA;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR = 0x93DB;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR = 0x93DC;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR = 0x93DD;
+
+    // Profile query support.
+    sequence<DOMString>? getSupportedProfiles();
+};
+
+[NoInterfaceObject]
 interface WEBGL_compressed_texture_atc
 {
     const GLenum COMPRESSED_RGB_ATC_WEBGL                     = 0x8C92;
     const GLenum COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL     = 0x8C93;
     const GLenum COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL = 0x87EE;
 };
 
 [NoInterfaceObject]
--- a/extensions/spellcheck/hunspell/glue/moz.build
+++ b/extensions/spellcheck/hunspell/glue/moz.build
@@ -1,15 +1,15 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
-UNIFIED_SOURCES += [
+SOURCES += [
     'mozHunspell.cpp',
     'mozHunspellDirProvider.cpp',
     'RemoteSpellCheckEngineChild.cpp',
     'RemoteSpellCheckEngineParent.cpp',
 ]
 
 CXXFLAGS += CONFIG['MOZ_HUNSPELL_CFLAGS']
 
--- a/extensions/spellcheck/hunspell/glue/mozHunspell.cpp
+++ b/extensions/spellcheck/hunspell/glue/mozHunspell.cpp
@@ -195,17 +195,17 @@ NS_IMETHODIMP mozHunspell::SetDictionary
   mDictionary = aDictionary;
   mAffixFileName = affFileName;
 
   mHunspell = new Hunspell(affFileName.get(),
                          dictFileName.get());
   if (!mHunspell)
     return NS_ERROR_OUT_OF_MEMORY;
 
-  nsAutoCString label(mHunspell->get_dict_encoding().c_str());
+  nsDependentCString label(mHunspell->get_dic_encoding());
   nsAutoCString encoding;
   if (!EncodingUtils::FindEncodingForLabelNoReplacement(label, encoding)) {
     return NS_ERROR_UCONV_NOCONV;
   }
   mEncoder = EncodingUtils::EncoderForEncoding(encoding);
   mDecoder = EncodingUtils::DecoderForEncoding(encoding);
 
   if (mEncoder)
@@ -475,34 +475,32 @@ mozHunspell::LoadDictionariesFromDir(nsI
     dict.ReplaceChar("_", '-');
 
     mDictionaries.Put(dict, file);
   }
 
   return NS_OK;
 }
 
-nsresult
-mozHunspell::ConvertCharset(const char16_t* aStr, std::string* aDst)
+nsresult mozHunspell::ConvertCharset(const char16_t* aStr, char ** aDst)
 {
   NS_ENSURE_ARG_POINTER(aDst);
   NS_ENSURE_TRUE(mEncoder, NS_ERROR_NULL_POINTER);
 
   int32_t outLength;
   int32_t inLength = NS_strlen(aStr);
   nsresult rv = mEncoder->GetMaxLength(aStr, inLength, &outLength);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  aDst->resize(outLength);
+  *aDst = (char *) moz_xmalloc(sizeof(char) * (outLength+1));
+  NS_ENSURE_TRUE(*aDst, NS_ERROR_OUT_OF_MEMORY);
 
-  char* dst = &aDst->operator[](0);
-  rv = mEncoder->Convert(aStr, &inLength, dst, &outLength);
-  if (NS_SUCCEEDED(rv)) {
-    aDst->resize(outLength);
-  }
+  rv = mEncoder->Convert(aStr, &inLength, *aDst, &outLength);
+  if (NS_SUCCEEDED(rv))
+    (*aDst)[outLength] = '\0';
 
   return rv;
 }
 
 NS_IMETHODIMP
 mozHunspell::CollectReports(nsIHandleReportCallback* aHandleReport,
                             nsISupports* aData, bool aAnonymize)
 {
@@ -515,74 +513,76 @@ mozHunspell::CollectReports(nsIHandleRep
 }
 
 NS_IMETHODIMP mozHunspell::Check(const char16_t *aWord, bool *aResult)
 {
   NS_ENSURE_ARG_POINTER(aWord);
   NS_ENSURE_ARG_POINTER(aResult);
   NS_ENSURE_TRUE(mHunspell, NS_ERROR_FAILURE);
 
-  std::string charsetWord;
-  nsresult rv = ConvertCharset(aWord, &charsetWord);
+  nsXPIDLCString charsetWord;
+  nsresult rv = ConvertCharset(aWord, getter_Copies(charsetWord));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  *aResult = mHunspell->spell(charsetWord);
+  *aResult = !!mHunspell->spell(charsetWord);
+
 
   if (!*aResult && mPersonalDictionary)
     rv = mPersonalDictionary->Check(aWord, mLanguage.get(), aResult);
 
   return rv;
 }
 
 NS_IMETHODIMP mozHunspell::Suggest(const char16_t *aWord, char16_t ***aSuggestions, uint32_t *aSuggestionCount)
 {
   NS_ENSURE_ARG_POINTER(aSuggestions);
   NS_ENSURE_ARG_POINTER(aSuggestionCount);
   NS_ENSURE_TRUE(mHunspell, NS_ERROR_FAILURE);
 
   nsresult rv;
   *aSuggestionCount = 0;
 
-  std::string charsetWord;
-  rv = ConvertCharset(aWord, &charsetWord);
+  nsXPIDLCString charsetWord;
+  rv = ConvertCharset(aWord, getter_Copies(charsetWord));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  std::vector<std::string> suggestions = mHunspell->suggest(charsetWord);
-  *aSuggestionCount = static_cast<uint32_t>(suggestions.size());
+  char ** wlst;
+  *aSuggestionCount = mHunspell->suggest(&wlst, charsetWord);
 
   if (*aSuggestionCount) {
     *aSuggestions  = (char16_t **)moz_xmalloc(*aSuggestionCount * sizeof(char16_t *));
     if (*aSuggestions) {
       uint32_t index = 0;
       for (index = 0; index < *aSuggestionCount && NS_SUCCEEDED(rv); ++index) {
         // Convert the suggestion to utf16
-        int32_t inLength = suggestions[index].size();
+        int32_t inLength = strlen(wlst[index]);
         int32_t outLength;
-        rv = mDecoder->GetMaxLength(suggestions[index].c_str(), inLength, &outLength);
+        rv = mDecoder->GetMaxLength(wlst[index], inLength, &outLength);
         if (NS_SUCCEEDED(rv))
         {
           (*aSuggestions)[index] = (char16_t *) moz_xmalloc(sizeof(char16_t) * (outLength+1));
           if ((*aSuggestions)[index])
           {
-            rv = mDecoder->Convert(suggestions[index].c_str(), &inLength, (*aSuggestions)[index], &outLength);
+            rv = mDecoder->Convert(wlst[index], &inLength, (*aSuggestions)[index], &outLength);
             if (NS_SUCCEEDED(rv))
               (*aSuggestions)[index][outLength] = 0;
           }
           else
             rv = NS_ERROR_OUT_OF_MEMORY;
         }
       }
 
       if (NS_FAILED(rv))
         NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(index, *aSuggestions); // free the char16_t strings up to the point at which the error occurred
     }
     else // if (*aSuggestions)
       rv = NS_ERROR_OUT_OF_MEMORY;
   }
 
+  NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(*aSuggestionCount, wlst);
   return rv;
 }
 
 NS_IMETHODIMP
 mozHunspell::Observe(nsISupports* aSubj, const char *aTopic,
                     const char16_t *aData)
 {
   NS_ASSERTION(!strcmp(aTopic, "profile-do-change")
--- a/extensions/spellcheck/hunspell/glue/mozHunspell.h
+++ b/extensions/spellcheck/hunspell/glue/mozHunspell.h
@@ -94,17 +94,17 @@ public:
 
   mozHunspell();
 
   nsresult Init();
 
   void LoadDictionaryList(bool aNotifyChildProcesses);
 
   // helper method for converting a word to the charset of the dictionary
-  nsresult ConvertCharset(const char16_t* aStr, std::string* aDst);
+  nsresult ConvertCharset(const char16_t* aStr, char ** aDst);
 
   NS_DECL_NSIMEMORYREPORTER
 
 protected:
   virtual ~mozHunspell();
 
   nsCOMPtr<mozIPersonalDictionary> mPersonalDictionary;
   nsCOMPtr<nsIUnicodeEncoder>      mEncoder;
--- a/extensions/spellcheck/hunspell/src/README.mozilla
+++ b/extensions/spellcheck/hunspell/src/README.mozilla
@@ -1,2 +1,2 @@
-Hunspell Version:   1.5.0
+Hunspell Version:   1.4.1
 Additional Patches: See patches directory.
--- a/extensions/spellcheck/hunspell/src/affentry.cxx
+++ b/extensions/spellcheck/hunspell/src/affentry.cxx
@@ -74,45 +74,62 @@
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <ctype.h>
 
 #include "affentry.hxx"
 #include "csutil.hxx"
 
-AffEntry::~AffEntry() {
+PfxEntry::PfxEntry(AffixMgr* pmgr, affentry* dp)
+    // register affix manager
+    : pmyMgr(pmgr),
+      next(NULL),
+      nexteq(NULL),
+      nextne(NULL),
+      flgnxt(NULL) {
+  // set up its initial values
+  aflag = dp->aflag;        // flag
+  strip = dp->strip;        // string to strip
+  appnd = dp->appnd;        // string to append
+  numconds = dp->numconds;  // length of the condition
+  opts = dp->opts;          // cross product flag
+  // then copy over all of the conditions
+  if (opts & aeLONGCOND) {
+    memcpy(c.conds, dp->c.l.conds1, MAXCONDLEN_1);
+    c.l.conds2 = dp->c.l.conds2;
+  } else
+    memcpy(c.conds, dp->c.conds, MAXCONDLEN);
+  morphcode = dp->morphcode;
+  contclass = dp->contclass;
+  contclasslen = dp->contclasslen;
+}
+
+PfxEntry::~PfxEntry() {
+  aflag = 0;
+  pmyMgr = NULL;
   if (opts & aeLONGCOND)
     free(c.l.conds2);
   if (morphcode && !(opts & aeALIASM))
     free(morphcode);
   if (contclass && !(opts & aeALIASF))
     free(contclass);
 }
 
-PfxEntry::PfxEntry(AffixMgr* pmgr)
-    // register affix manager
-    : pmyMgr(pmgr),
-      next(NULL),
-      nexteq(NULL),
-      nextne(NULL),
-      flgnxt(NULL) {
-}
-
 // add prefix to this word assuming conditions hold
-std::string PfxEntry::add(const char* word, size_t len) {
-  std::string result;
+char* PfxEntry::add(const char* word, size_t len) {
   if ((len > strip.size() || (len == 0 && pmyMgr->get_fullstrip())) &&
       (len >= numconds) && test_condition(word) &&
       (!strip.size() || (strncmp(word, strip.c_str(), strip.size()) == 0))) {
     /* we have a match so add prefix */
-    result.assign(appnd);
-    result.append(word + strip.size());
+    std::string tword(appnd);
+    tword.append(word + strip.size());
+    return mystrdup(tword.c_str());
   }
-  return result;
+  return NULL;
 }
 
 inline char* PfxEntry::nextchar(char* p) {
   if (p) {
     p++;
     if (opts & aeLONGCOND) {
       // jump to the 2nd part of the condition
       if (p == c.conds + MAXCONDLEN_1)
@@ -254,30 +271,33 @@ struct hentry* PfxEntry::checkword(const
 
       // prefix matched but no root word was found
       // if aeXPRODUCT is allowed, try again but now
       // ross checked combined with a suffix
 
       // if ((opts & aeXPRODUCT) && in_compound) {
       if ((opts & aeXPRODUCT)) {
         he = pmyMgr->suffix_check(tmpword.c_str(), tmpl, aeXPRODUCT, this,
-                                  FLAG_NULL, needflag, in_compound);
+                                  NULL, 0, NULL, FLAG_NULL, needflag,
+                                  in_compound);
         if (he)
           return he;
       }
     }
   }
   return NULL;
 }
 
 // check if this prefix entry matches
 struct hentry* PfxEntry::check_twosfx(const char* word,
                                       int len,
                                       char in_compound,
                                       const FLAG needflag) {
+  struct hentry* he;  // hash entry of root word or NULL
+
   // on entry prefix is 0 length or already matches the beginning of the word.
   // So if the remaining root word has positive length
   // and if there are enough chars in root word and added back strip chars
   // to meet the number of characters conditions, then test it
 
   int tmpl = len - appnd.size(); // length of tmpword
 
   if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) &&
@@ -299,37 +319,36 @@ struct hentry* PfxEntry::check_twosfx(co
     if (test_condition(tmpword.c_str())) {
       tmpl += strip.size();
 
       // prefix matched but no root word was found
       // if aeXPRODUCT is allowed, try again but now
       // cross checked combined with a suffix
 
       if ((opts & aeXPRODUCT) && (in_compound != IN_CPD_BEGIN)) {
-        // hash entry of root word or NULL
-        struct hentry* he = pmyMgr->suffix_check_twosfx(tmpword.c_str(), tmpl, aeXPRODUCT, this,
-                                                        needflag);
+        he = pmyMgr->suffix_check_twosfx(tmpword.c_str(), tmpl, aeXPRODUCT, this,
+                                         needflag);
         if (he)
           return he;
       }
     }
   }
   return NULL;
 }
 
 // check if this prefix entry matches
-std::string PfxEntry::check_twosfx_morph(const char* word,
-                                         int len,
-                                         char in_compound,
-                                         const FLAG needflag) {
-  std::string result;
+char* PfxEntry::check_twosfx_morph(const char* word,
+                                   int len,
+                                   char in_compound,
+                                   const FLAG needflag) {
   // on entry prefix is 0 length or already matches the beginning of the word.
   // So if the remaining root word has positive length
   // and if there are enough chars in root word and added back strip chars
   // to meet the number of characters conditions, then test it
+
   int tmpl = len - appnd.size(); // length of tmpword
 
   if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) &&
       (tmpl + strip.size() >= numconds)) {
     // generate new root word by removing prefix and adding
     // back any characters that would have been stripped
 
     std::string tmpword(strip);
@@ -346,31 +365,32 @@ std::string PfxEntry::check_twosfx_morph
     if (test_condition(tmpword.c_str())) {
       tmpl += strip.size();
 
       // prefix matched but no root word was found
       // if aeXPRODUCT is allowed, try again but now
       // ross checked combined with a suffix
 
       if ((opts & aeXPRODUCT) && (in_compound != IN_CPD_BEGIN)) {
-        result = pmyMgr->suffix_check_twosfx_morph(tmpword.c_str(), tmpl,
-                                                   aeXPRODUCT,
-                                                   this, needflag);
+        return pmyMgr->suffix_check_twosfx_morph(tmpword.c_str(), tmpl,
+                                                 aeXPRODUCT,
+                                                 this, needflag);
       }
     }
   }
-  return result;
+  return NULL;
 }
 
 // check if this prefix entry matches
-std::string PfxEntry::check_morph(const char* word,
-                                  int len,
-                                  char in_compound,
-                                  const FLAG needflag) {
-  std::string result;
+char* PfxEntry::check_morph(const char* word,
+                            int len,
+                            char in_compound,
+                            const FLAG needflag) {
+  struct hentry* he;  // hash entry of root word or NULL
+  char* st;
 
   // on entry prefix is 0 length or already matches the beginning of the word.
   // So if the remaining root word has positive length
   // and if there are enough chars in root word and added back strip chars
   // to meet the number of characters conditions, then test it
 
   int tmpl = len - appnd.size(); // length of tmpword
 
@@ -386,18 +406,19 @@ std::string PfxEntry::check_morph(const 
     // are met.  Please see the appendix at the end of
     // this file for more info on exactly what is being
     // tested
 
     // if all conditions are met then check if resulting
     // root word in the dictionary
 
     if (test_condition(tmpword.c_str())) {
+      std::string result;
+
       tmpl += strip.size();
-      struct hentry* he;  // hash entry of root word or NULL
       if ((he = pmyMgr->lookup(tmpword.c_str())) != NULL) {
         do {
           if (TESTAFF(he->astr, aflag, he->alen) &&
               // forbid single prefixes with needaffix flag
               !TESTAFF(contclass, pmyMgr->get_needaffix(), contclasslen) &&
               // needflag
               ((!needflag) || TESTAFF(he->astr, needflag, he->alen) ||
                (contclass && TESTAFF(contclass, needflag, contclasslen)))) {
@@ -429,53 +450,86 @@ std::string PfxEntry::check_morph(const 
         } while (he);
       }
 
       // prefix matched but no root word was found
       // if aeXPRODUCT is allowed, try again but now
       // ross checked combined with a suffix
 
       if ((opts & aeXPRODUCT) && (in_compound != IN_CPD_BEGIN)) {
-        std::string st = pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, aeXPRODUCT, this,
-                                                    FLAG_NULL, needflag);
-        if (!st.empty()) {
+        st = pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, aeXPRODUCT, this,
+                                        FLAG_NULL, needflag);
+        if (st) {
           result.append(st);
+          free(st);
         }
       }
+
+      if (!result.empty())
+        return mystrdup(result.c_str());
     }
   }
 
-  return result;
+  return NULL;
 }
 
-SfxEntry::SfxEntry(AffixMgr* pmgr)
+SfxEntry::SfxEntry(AffixMgr* pmgr, affentry* dp)
     : pmyMgr(pmgr)  // register affix manager
       ,
       next(NULL),
       nexteq(NULL),
       nextne(NULL),
       flgnxt(NULL),
       l_morph(NULL),
       r_morph(NULL),
       eq_morph(NULL) {
+  // set up its initial values
+  aflag = dp->aflag;        // char flag
+  strip = dp->strip;        // string to strip
+  appnd = dp->appnd;        // string to append
+  numconds = dp->numconds;  // length of the condition
+  opts = dp->opts;          // cross product flag
+
+  // then copy over all of the conditions
+  if (opts & aeLONGCOND) {
+    memcpy(c.l.conds1, dp->c.l.conds1, MAXCONDLEN_1);
+    c.l.conds2 = dp->c.l.conds2;
+  } else
+    memcpy(c.conds, dp->c.conds, MAXCONDLEN);
+  rappnd = appnd;
+  reverseword(rappnd);
+  morphcode = dp->morphcode;
+  contclass = dp->contclass;
+  contclasslen = dp->contclasslen;
+}
+
+SfxEntry::~SfxEntry() {
+  aflag = 0;
+  pmyMgr = NULL;
+  if (opts & aeLONGCOND)
+    free(c.l.conds2);
+  if (morphcode && !(opts & aeALIASM))
+    free(morphcode);
+  if (contclass && !(opts & aeALIASF))
+    free(contclass);
 }
 
 // add suffix to this word assuming conditions hold
-std::string SfxEntry::add(const char* word, size_t len) {
-  std::string result;
+char* SfxEntry::add(const char* word, size_t len) {
   /* make sure all conditions match */
   if ((len > strip.size() || (len == 0 && pmyMgr->get_fullstrip())) &&
       (len >= numconds) && test_condition(word + len, word) &&
       (!strip.size() ||
        (strcmp(word + len - strip.size(), strip.c_str()) == 0))) {
-    result.assign(word);
+    std::string tword(word);
     /* we have a match so add suffix */
-    result.replace(len - strip.size(), std::string::npos, appnd);
+    tword.replace(len - strip.size(), std::string::npos, appnd);
+    return mystrdup(tword.c_str());
   }
-  return result;
+  return NULL;
 }
 
 inline char* SfxEntry::nextchar(char* p) {
   if (p) {
     p++;
     if (opts & aeLONGCOND) {
       // jump to the 2nd part of the condition
       if (p == c.l.conds1 + MAXCONDLEN_1)
@@ -610,16 +664,19 @@ inline int SfxEntry::test_condition(cons
   }
 }
 
 // see if this suffix is present in the word
 struct hentry* SfxEntry::checkword(const char* word,
                                    int len,
                                    int optflags,
                                    PfxEntry* ppfx,
+                                   char** wlst,
+                                   int maxSug,
+                                   int* ns,
                                    const FLAG cclass,
                                    const FLAG needflag,
                                    const FLAG badflag) {
   struct hentry* he;  // hash entry pointer
   PfxEntry* ep = ppfx;
 
   // if this suffix is being cross checked with a prefix
   // but it does not support cross products skip it
@@ -680,28 +737,50 @@ struct hentry* SfxEntry::checkword(const
               (!badflag || !TESTAFF(he->astr, badflag, he->alen)) &&
               // handle required flag
               ((!needflag) ||
                (TESTAFF(he->astr, needflag, he->alen) ||
                 ((contclass) && TESTAFF(contclass, needflag, contclasslen)))))
             return he;
           he = he->next_homonym;  // check homonyms
         } while (he);
+
+        // obsolote stemming code (used only by the
+        // experimental SuffixMgr:suggest_pos_stems)
+        // store resulting root in wlst
+      } else if (wlst && (*ns < maxSug)) {
+        int cwrd = 1;
+        for (int k = 0; k < *ns; k++)
+          if (strcmp(tmpword, wlst[k]) == 0) {
+            cwrd = 0;
+            break;
+          }
+        if (cwrd) {
+          wlst[*ns] = mystrdup(tmpword);
+          if (wlst[*ns] == NULL) {
+            for (int j = 0; j < *ns; j++)
+              free(wlst[j]);
+            *ns = -1;
+            return NULL;
+          }
+          (*ns)++;
+        }
       }
     }
   }
   return NULL;
 }
 
 // see if two-level suffix is present in the word
 struct hentry* SfxEntry::check_twosfx(const char* word,
                                       int len,
                                       int optflags,
                                       PfxEntry* ppfx,
                                       const FLAG needflag) {
+  struct hentry* he;  // hash entry pointer
   PfxEntry* ep = ppfx;
 
   // if this suffix is being cross checked with a prefix
   // but it does not support cross products skip it
 
   if ((optflags & aeXPRODUCT) != 0 && (opts & aeXPRODUCT) == 0)
     return NULL;
 
@@ -729,51 +808,53 @@ struct hentry* SfxEntry::check_twosfx(co
     // now make sure all of the conditions on characters
     // are met.  Please see the appendix at the end of
     // this file for more info on exactly what is being
     // tested
 
     // if all conditions are met then recall suffix_check
 
     if (test_condition(end, beg)) {
-      struct hentry* he;  // hash entry pointer
       if (ppfx) {
         // handle conditional suffix
         if ((contclass) && TESTAFF(contclass, ep->getFlag(), contclasslen))
-          he = pmyMgr->suffix_check(tmpword.c_str(), tmpl, 0, NULL,
-                                    (FLAG)aflag, needflag, IN_CPD_NOT);
+          he = pmyMgr->suffix_check(tmpword.c_str(), tmpl, 0, NULL, NULL, 0, NULL,
+                                    (FLAG)aflag, needflag);
         else
-          he = pmyMgr->suffix_check(tmpword.c_str(), tmpl, optflags, ppfx,
-                                    (FLAG)aflag, needflag, IN_CPD_NOT);
+          he = pmyMgr->suffix_check(tmpword.c_str(), tmpl, optflags, ppfx, NULL, 0,
+                                    NULL, (FLAG)aflag, needflag);
       } else {
-        he = pmyMgr->suffix_check(tmpword.c_str(), tmpl, 0, NULL,
-                                  (FLAG)aflag, needflag, IN_CPD_NOT);
+        he = pmyMgr->suffix_check(tmpword.c_str(), tmpl, 0, NULL, NULL, 0, NULL,
+                                  (FLAG)aflag, needflag);
       }
       if (he)
         return he;
     }
   }
   return NULL;
 }
 
 // see if two-level suffix is present in the word
-std::string SfxEntry::check_twosfx_morph(const char* word,
-                                         int len,
-                                         int optflags,
-                                         PfxEntry* ppfx,
-                                         const FLAG needflag) {
+char* SfxEntry::check_twosfx_morph(const char* word,
+                                   int len,
+                                   int optflags,
+                                   PfxEntry* ppfx,
+                                   const FLAG needflag) {
   PfxEntry* ep = ppfx;
+  char* st;
 
-  std::string result;
+  char result[MAXLNLEN];
+
+  *result = '\0';
 
   // if this suffix is being cross checked with a prefix
   // but it does not support cross products skip it
 
   if ((optflags & aeXPRODUCT) != 0 && (opts & aeXPRODUCT) == 0)
-    return result;
+    return NULL;
 
   // upon entry suffix is 0 length or already matches the end of the word.
   // So if the remaining root word has positive length
   // and if there are enough chars in root word and added back strip chars
   // to meet the number of characters conditions, then test it
 
   int tmpl = len - appnd.size(); // length of tmpword
 
@@ -797,44 +878,50 @@ std::string SfxEntry::check_twosfx_morph
     // tested
 
     // if all conditions are met then recall suffix_check
 
     if (test_condition(end, beg)) {
       if (ppfx) {
         // handle conditional suffix
         if ((contclass) && TESTAFF(contclass, ep->getFlag(), contclasslen)) {
-          std::string st = pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, 0, NULL, aflag,
-                                                      needflag);
-          if (!st.empty()) {
+          st = pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, 0, NULL, aflag,
+                                          needflag);
+          if (st) {
             if (ppfx->getMorph()) {
-              result.append(ppfx->getMorph());
-              result.append(" ");
+              mystrcat(result, ppfx->getMorph(), MAXLNLEN);
+              mystrcat(result, " ", MAXLNLEN);
             }
-            result.append(st);
+            mystrcat(result, st, MAXLNLEN);
+            free(st);
             mychomp(result);
           }
         } else {
-          std::string st = pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, optflags, ppfx, aflag,
-                                                      needflag);
-          if (!st.empty()) {
-            result.append(st);
+          st = pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, optflags, ppfx, aflag,
+                                          needflag);
+          if (st) {
+            mystrcat(result, st, MAXLNLEN);
+            free(st);
             mychomp(result);
           }
         }
       } else {
-        std::string st = pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, 0, NULL, aflag, needflag);
-        if (!st.empty()) {
-          result.append(st);
+        st =
+            pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, 0, NULL, aflag, needflag);
+        if (st) {
+          mystrcat(result, st, MAXLNLEN);
+          free(st);
           mychomp(result);
         }
       }
+      if (*result)
+        return mystrdup(result);
     }
   }
-  return result;
+  return NULL;
 }
 
 // get next homonym with same affix
 struct hentry* SfxEntry::get_next_homonym(struct hentry* he,
                                           int optflags,
                                           PfxEntry* ppfx,
                                           const FLAG cclass,
                                           const FLAG needflag) {
@@ -856,21 +943,16 @@ struct hentry* SfxEntry::get_next_homony
         ((!needflag) ||
          (TESTAFF(he->astr, needflag, he->alen) ||
           ((contclass) && TESTAFF(contclass, needflag, contclasslen)))))
       return he;
   }
   return NULL;
 }
 
-void SfxEntry::initReverseWord() {
-  rappnd = appnd;
-  reverseword(rappnd);
-}
-
 #if 0
 
 Appendix:  Understanding Affix Code
 
 
 An affix is either a  prefix or a suffix attached to root words to make 
 other words.
 
--- a/extensions/spellcheck/hunspell/src/affentry.hxx
+++ b/extensions/spellcheck/hunspell/src/affentry.hxx
@@ -66,65 +66,68 @@
  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
-#ifndef AFFIX_HXX_
-#define AFFIX_HXX_
+#ifndef _AFFIX_HXX_
+#define _AFFIX_HXX_
+
+#include "hunvisapi.h"
 
 #include "atypes.hxx"
 #include "baseaffix.hxx"
 #include "affixmgr.hxx"
 
 /* A Prefix Entry  */
 
-class PfxEntry : public AffEntry {
+class LIBHUNSPELL_DLL_EXPORTED PfxEntry : protected AffEntry {
  private:
   PfxEntry(const PfxEntry&);
   PfxEntry& operator=(const PfxEntry&);
 
  private:
   AffixMgr* pmyMgr;
 
   PfxEntry* next;
   PfxEntry* nexteq;
   PfxEntry* nextne;
   PfxEntry* flgnxt;
 
  public:
-  explicit PfxEntry(AffixMgr* pmgr);
+  PfxEntry(AffixMgr* pmgr, affentry* dp);
+  ~PfxEntry();
 
-  bool allowCross() const { return ((opts & aeXPRODUCT) != 0); }
+  inline bool allowCross() { return ((opts & aeXPRODUCT) != 0); }
   struct hentry* checkword(const char* word,
                            int len,
                            char in_compound,
                            const FLAG needflag = FLAG_NULL);
 
   struct hentry* check_twosfx(const char* word,
                               int len,
                               char in_compound,
                               const FLAG needflag = FLAG_NULL);
 
-  std::string check_morph(const char* word,
-                          int len,
-                          char in_compound,
-                          const FLAG needflag = FLAG_NULL);
+  char* check_morph(const char* word,
+                    int len,
+                    char in_compound,
+                    const FLAG needflag = FLAG_NULL);
 
-  std::string check_twosfx_morph(const char* word,
-                                 int len,
-                                 char in_compound,
-                                 const FLAG needflag = FLAG_NULL);
+  char* check_twosfx_morph(const char* word,
+                           int len,
+                           char in_compound,
+                           const FLAG needflag = FLAG_NULL);
 
-  FLAG getFlag() { return aflag; }
-  const char* getKey() { return appnd.c_str(); }
-  std::string add(const char* word, size_t len);
+  inline FLAG getFlag() { return aflag; }
+  inline const char* getKey() { return appnd.c_str(); }
+  char* add(const char* word, size_t len);
 
   inline short getKeyLen() { return appnd.size(); }
 
   inline const char* getMorph() { return morphcode; }
 
   inline const unsigned short* getCont() { return contclass; }
   inline short getContLen() { return contclasslen; }
 
@@ -139,17 +142,17 @@ class PfxEntry : public AffEntry {
   inline void setFlgNxt(PfxEntry* ptr) { flgnxt = ptr; }
 
   inline char* nextchar(char* p);
   inline int test_condition(const char* st);
 };
 
 /* A Suffix Entry */
 
-class SfxEntry : public AffEntry {
+class LIBHUNSPELL_DLL_EXPORTED SfxEntry : protected AffEntry {
  private:
   SfxEntry(const SfxEntry&);
   SfxEntry& operator=(const SfxEntry&);
 
  private:
   AffixMgr* pmyMgr;
   std::string rappnd;
 
@@ -158,48 +161,52 @@ class SfxEntry : public AffEntry {
   SfxEntry* nextne;
   SfxEntry* flgnxt;
 
   SfxEntry* l_morph;
   SfxEntry* r_morph;
   SfxEntry* eq_morph;
 
  public:
-  explicit SfxEntry(AffixMgr* pmgr);
+  SfxEntry(AffixMgr* pmgr, affentry* dp);
+  ~SfxEntry();
 
-  bool allowCross() const { return ((opts & aeXPRODUCT) != 0); }
+  inline bool allowCross() { return ((opts & aeXPRODUCT) != 0); }
   struct hentry* checkword(const char* word,
                            int len,
                            int optflags,
                            PfxEntry* ppfx,
-                           const FLAG cclass,
-                           const FLAG needflag,
-                           const FLAG badflag);
+                           char** wlst,
+                           int maxSug,
+                           int* ns,
+                           const FLAG cclass = FLAG_NULL,
+                           const FLAG needflag = FLAG_NULL,
+                           const FLAG badflag = FLAG_NULL);
 
   struct hentry* check_twosfx(const char* word,
                               int len,
                               int optflags,
                               PfxEntry* ppfx,
                               const FLAG needflag = FLAG_NULL);
 
-  std::string check_twosfx_morph(const char* word,
-                                 int len,
-                                 int optflags,
-                                 PfxEntry* ppfx,
-                                 const FLAG needflag = FLAG_NULL);
+  char* check_twosfx_morph(const char* word,
+                           int len,
+                           int optflags,
+                           PfxEntry* ppfx,
+                           const FLAG needflag = FLAG_NULL);
   struct hentry* get_next_homonym(struct hentry* he);
   struct hentry* get_next_homonym(struct hentry* word,
                                   int optflags,
                                   PfxEntry* ppfx,
                                   const FLAG cclass,
                                   const FLAG needflag);
 
-  FLAG getFlag() { return aflag; }
-  const char* getKey() { return rappnd.c_str(); }
-  std::string add(const char* word, size_t len);
+  inline FLAG getFlag() { return aflag; }
+  inline const char* getKey() { return rappnd.c_str(); }
+  char* add(const char* word, size_t len);
 
   inline const char* getMorph() { return morphcode; }
 
   inline const unsigned short* getCont() { return contclass; }
   inline short getContLen() { return contclasslen; }
   inline const char* getAffix() { return appnd.c_str(); }
 
   inline short getKeyLen() { return appnd.size(); }
@@ -212,15 +219,14 @@ class SfxEntry : public AffEntry {
   inline SfxEntry* getRM() { return r_morph; }
   inline SfxEntry* getEQM() { return eq_morph; }
   inline SfxEntry* getFlgNxt() { return flgnxt; }
 
   inline void setNext(SfxEntry* ptr) { next = ptr; }
   inline void setNextNE(SfxEntry* ptr) { nextne = ptr; }
   inline void setNextEQ(SfxEntry* ptr) { nexteq = ptr; }
   inline void setFlgNxt(SfxEntry* ptr) { flgnxt = ptr; }
-  void initReverseWord();
 
   inline char* nextchar(char* p);
   inline int test_condition(const char* st, const char* begin);
 };
 
 #endif
--- a/extensions/spellcheck/hunspell/src/affixmgr.cxx
+++ b/extensions/spellcheck/hunspell/src/affixmgr.cxx
@@ -83,34 +83,43 @@
 
 #include "affixmgr.hxx"
 #include "affentry.hxx"
 #include "langnum.hxx"
 
 #include "csutil.hxx"
 
 AffixMgr::AffixMgr(const char* affpath,
-                   const std::vector<HashMgr*>& ptr,
-                   const char* key)
-  : alldic(ptr)
-  , pHMgr(ptr[0]) {
-
+                   HashMgr** ptr,
+                   int* md,
+                   const char* key) {
   // register hash manager and load affix data from aff file
+  pHMgr = ptr[0];
+  alldic = ptr;
+  maxdic = md;
+  keystring = NULL;
+  trystring = NULL;
+  encoding = NULL;
   csconv = NULL;
   utf8 = 0;
   complexprefixes = 0;
-  parsedmaptable = false;
-  parsedbreaktable = false;
-  parsedrep = false;
+  maptable = NULL;
+  nummap = 0;
+  breaktable = NULL;
+  numbreak = -1;
+  reptable = NULL;
+  numrep = 0;
   iconvtable = NULL;
   oconvtable = NULL;
+  checkcpdtable = NULL;
   // allow simplified compound forms (see 3rd field of CHECKCOMPOUNDPATTERN)
   simplifiedcpd = 0;
-  parsedcheckcpd = false;
-  parseddefcpd = false;
+  numcheckcpd = 0;
+  defcpdtable = NULL;
+  numdefcpd = 0;
   phone = NULL;
   compoundflag = FLAG_NULL;        // permits word in compound forms
   compoundbegin = FLAG_NULL;       // may be first word in compound forms
   compoundmiddle = FLAG_NULL;      // may be middle word in compound forms
   compoundend = FLAG_NULL;         // may be last word in compound forms
   compoundroot = FLAG_NULL;        // compound word signing flag
   compoundpermitflag = FLAG_NULL;  // compound permitting flag for suffixed word
   compoundforbidflag = FLAG_NULL;  // compound fordidden flag for suffixed word
@@ -121,25 +130,35 @@ AffixMgr::AffixMgr(const char* affpath,
   checkcompoundcase =
       0;  // forbid upper and lowercase combinations at word bounds
   checkcompoundtriple = 0;  // forbid compounds with triple letters
   simplifiedtriple = 0;     // allow simplified triple letters in compounds
                             // (Schiff+fahrt -> Schiffahrt)
   forbiddenword = FORBIDDENWORD;  // forbidden word signing flag
   nosuggest = FLAG_NULL;  // don't suggest words signed with NOSUGGEST flag
   nongramsuggest = FLAG_NULL;
+  lang = NULL;  // language
   langnum = 0;  // language code (see http://l10n.openoffice.org/languages.html)
   needaffix = FLAG_NULL;  // forbidden root, allowed only with suffixes
   cpdwordmax = -1;        // default: unlimited wordcount in compound words
   cpdmin = -1;            // undefined
   cpdmaxsyllable = 0;     // default: unlimited syllablecount in compound words
+  cpdvowels = NULL;  // vowels (for calculating of Hungarian compounding limit,
+                     // O(n) search! XXX)
+  cpdvowels_utf16 =
+      NULL;  // vowels for UTF-8 encoding (bsearch instead of O(n) search)
+  cpdvowels_utf16_len = 0;  // vowels
   pfxappnd = NULL;  // previous prefix for counting syllables of the prefix BUG
   sfxappnd = NULL;  // previous suffix for counting syllables of the suffix BUG
   sfxextra = 0;     // modifier for syllable count of sfxappnd BUG
+  cpdsyllablenum = NULL;      // syllable count incrementing flag
   checknum = 0;               // checking numbers, and word with numbers
+  wordchars = NULL;           // letters + spec. word characters
+  ignorechars = NULL;         // letters + spec. word characters
+  version = NULL;             // affix and dictionary file version string
   havecontclass = 0;  // flags of possible continuing classes (double affix)
   // LEMMA_PRESENT: not put root into the morphological output. Lemma presents
   // in morhological description in dictionary file. It's often combined with
   // PSEUDOROOT.
   lemma_present = FLAG_NULL;
   circumfix = FLAG_NULL;
   onlyincompound = FLAG_NULL;
   maxngramsugs = -1;  // undefined
@@ -201,20 +220,93 @@ AffixMgr::~AffixMgr() {
       nptr = ptr->getNext();
       delete (ptr);
       ptr = nptr;
       nptr = NULL;
     }
     sStart[j] = NULL;
   }
 
-  delete iconvtable;
-  delete oconvtable;
-  delete phone;
-
+  if (keystring)
+    free(keystring);
+  keystring = NULL;
+  if (trystring)
+    free(trystring);
+  trystring = NULL;
+  if (encoding)
+    free(encoding);
+  encoding = NULL;
+  if (maptable) {
+    for (int j = 0; j < nummap; j++) {
+      for (int k = 0; k < maptable[j].len; k++) {
+        if (maptable[j].set[k])
+          free(maptable[j].set[k]);
+      }
+      free(maptable[j].set);
+      maptable[j].set = NULL;
+      maptable[j].len = 0;
+    }
+    free(maptable);
+    maptable = NULL;
+  }
+  nummap = 0;
+  if (breaktable) {
+    for (int j = 0; j < numbreak; j++) {
+      if (breaktable[j])
+        free(breaktable[j]);
+      breaktable[j] = NULL;
+    }
+    free(breaktable);
+    breaktable = NULL;
+  }
+  numbreak = 0;
+  if (reptable) {
+    for (int j = 0; j < numrep; j++) {
+      free(reptable[j].pattern);
+      free(reptable[j].pattern2);
+    }
+    free(reptable);
+    reptable = NULL;
+  }
+  if (iconvtable)
+    delete iconvtable;
+  if (oconvtable)
+    delete oconvtable;
+  if (phone && phone->rules) {
+    for (int j = 0; j < phone->num + 1; j++) {
+      free(phone->rules[j * 2]);
+      free(phone->rules[j * 2 + 1]);
+    }
+    free(phone->rules);
+    free(phone);
+    phone = NULL;
+  }
+
+  if (defcpdtable) {
+    for (int j = 0; j < numdefcpd; j++) {
+      free(defcpdtable[j].def);
+      defcpdtable[j].def = NULL;
+    }
+    free(defcpdtable);
+    defcpdtable = NULL;
+  }
+  numrep = 0;
+  if (checkcpdtable) {
+    for (int j = 0; j < numcheckcpd; j++) {
+      free(checkcpdtable[j].pattern);
+      free(checkcpdtable[j].pattern2);
+      free(checkcpdtable[j].pattern3);
+      checkcpdtable[j].pattern = NULL;
+      checkcpdtable[j].pattern2 = NULL;
+      checkcpdtable[j].pattern3 = NULL;
+    }
+    free(checkcpdtable);
+    checkcpdtable = NULL;
+  }
+  numcheckcpd = 0;
   FREE_FLAG(compoundflag);
   FREE_FLAG(compoundbegin);
   FREE_FLAG(compoundmiddle);
   FREE_FLAG(compoundend);
   FREE_FLAG(compoundpermitflag);
   FREE_FLAG(compoundforbidflag);
   FREE_FLAG(compoundroot);
   FREE_FLAG(forbiddenword);
@@ -224,33 +316,49 @@ AffixMgr::~AffixMgr() {
   FREE_FLAG(lemma_present);
   FREE_FLAG(circumfix);
   FREE_FLAG(onlyincompound);
 
   cpdwordmax = 0;
   pHMgr = NULL;
   cpdmin = 0;
   cpdmaxsyllable = 0;
+  if (cpdvowels)
+    free(cpdvowels);
+  if (cpdvowels_utf16)
+    free(cpdvowels_utf16);
+  if (cpdsyllablenum)
+    free(cpdsyllablenum);
   free_utf_tbl();
+  if (lang)
+    free(lang);
+  if (wordchars)
+    free(wordchars);
+  if (ignorechars)
+    free(ignorechars);
+  if (version)
+    free(version);
   checknum = 0;
 #ifdef MOZILLA_CLIENT
   delete[] csconv;
 #endif
 }
 
 void AffixMgr::finishFileMgr(FileMgr* afflst) {
   delete afflst;
 
   // convert affix trees to sorted list
   process_pfx_tree_to_list();
   process_sfx_tree_to_list();
 }
 
 // read in aff file and build up prefix and suffix entry objects
 int AffixMgr::parse_file(const char* affpath, const char* key) {
+  char* line;  // io buffers
+  char ft;     // affix type
 
   // checking flag duplication
   char dupflags[CONTSIZE];
   char dupflags_ini = 1;
 
   // first line indicator for removing byte order mark
   int firstline = 1;
 
@@ -262,450 +370,449 @@ int AffixMgr::parse_file(const char* aff
     return 1;
   }
 
   // step one is to parse the affix file building up the internal
   // affix data structures
 
   // read in each line ignoring any that do not
   // start with a known line type indicator
-  std::string line;
-  while (afflst->getline(line)) {
+  while ((line = afflst->getline()) != NULL) {
     mychomp(line);
 
     /* remove byte order mark */
     if (firstline) {
       firstline = 0;
       // Affix file begins with byte order mark: possible incompatibility with
       // old Hunspell versions
-      if (line.compare(0, 3, "\xEF\xBB\xBF", 3) == 0) {
-        line.erase(0, 3);
+      if (strncmp(line, "\xEF\xBB\xBF", 3) == 0) {
+        memmove(line, line + 3, strlen(line + 3) + 1);
       }
     }
 
     /* parse in the keyboard string */
-    if (line.compare(0, 3, "KEY", 3) == 0) {
-      if (!parse_string(line, keystring, afflst->getlinenum())) {
+    if (strncmp(line, "KEY", 3) == 0) {
+      if (parse_string(line, &keystring, afflst->getlinenum())) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the try string */
-    if (line.compare(0, 3, "TRY", 3) == 0) {
-      if (!parse_string(line, trystring, afflst->getlinenum())) {
+    if (strncmp(line, "TRY", 3) == 0) {
+      if (parse_string(line, &trystring, afflst->getlinenum())) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the name of the character set used by the .dict and .aff */
-    if (line.compare(0, 3, "SET", 3) == 0) {
-      if (!parse_string(line, encoding, afflst->getlinenum())) {
+    if (strncmp(line, "SET", 3) == 0) {
+      if (parse_string(line, &encoding, afflst->getlinenum())) {
         finishFileMgr(afflst);
         return 1;
       }
-      if (encoding == "UTF-8") {
+      if (strcmp(encoding, "UTF-8") == 0) {
         utf8 = 1;
 #ifndef OPENOFFICEORG
 #ifndef MOZILLA_CLIENT
-        initialize_utf_tbl();
+        if (initialize_utf_tbl()) {
+          finishFileMgr(afflst);
+          return 1;
+        }
 #endif
 #endif
       }
     }
 
     /* parse COMPLEXPREFIXES for agglutinative languages with right-to-left
      * writing system */
-    if (line.compare(0, 15, "COMPLEXPREFIXES", 15) == 0)
+    if (strncmp(line, "COMPLEXPREFIXES", 15) == 0)
       complexprefixes = 1;
 
     /* parse in the flag used by the controlled compound words */
-    if (line.compare(0, 12, "COMPOUNDFLAG", 12) == 0) {
-      if (!parse_flag(line, &compoundflag, afflst)) {
+    if (strncmp(line, "COMPOUNDFLAG", 12) == 0) {
+      if (parse_flag(line, &compoundflag, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag used by compound words */
-    if (line.compare(0, 13, "COMPOUNDBEGIN", 13) == 0) {
+    if (strncmp(line, "COMPOUNDBEGIN", 13) == 0) {
       if (complexprefixes) {
-        if (!parse_flag(line, &compoundend, afflst)) {
+        if (parse_flag(line, &compoundend, afflst)) {
           finishFileMgr(afflst);
           return 1;
         }
       } else {
-        if (!parse_flag(line, &compoundbegin, afflst)) {
+        if (parse_flag(line, &compoundbegin, afflst)) {
           finishFileMgr(afflst);
           return 1;
         }
       }
     }
 
     /* parse in the flag used by compound words */
-    if (line.compare(0, 14, "COMPOUNDMIDDLE", 14) == 0) {
-      if (!parse_flag(line, &compoundmiddle, afflst)) {
+    if (strncmp(line, "COMPOUNDMIDDLE", 14) == 0) {
+      if (parse_flag(line, &compoundmiddle, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
-
     /* parse in the flag used by compound words */
-    if (line.compare(0, 11, "COMPOUNDEND", 11) == 0) {
+    if (strncmp(line, "COMPOUNDEND", 11) == 0) {
       if (complexprefixes) {
-        if (!parse_flag(line, &compoundbegin, afflst)) {
+        if (parse_flag(line, &compoundbegin, afflst)) {
           finishFileMgr(afflst);
           return 1;
         }
       } else {
-        if (!parse_flag(line, &compoundend, afflst)) {
+        if (parse_flag(line, &compoundend, afflst)) {
           finishFileMgr(afflst);
           return 1;
         }
       }
     }
 
     /* parse in the data used by compound_check() method */
-    if (line.compare(0, 15, "COMPOUNDWORDMAX", 15) == 0) {
-      if (!parse_num(line, &cpdwordmax, afflst)) {
+    if (strncmp(line, "COMPOUNDWORDMAX", 15) == 0) {
+      if (parse_num(line, &cpdwordmax, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag sign compounds in dictionary */
-    if (line.compare(0, 12, "COMPOUNDROOT", 12) == 0) {
-      if (!parse_flag(line, &compoundroot, afflst)) {
+    if (strncmp(line, "COMPOUNDROOT", 12) == 0) {
+      if (parse_flag(line, &compoundroot, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag used by compound_check() method */
-    if (line.compare(0, 18, "COMPOUNDPERMITFLAG", 18) == 0) {
-      if (!parse_flag(line, &compoundpermitflag, afflst)) {
+    if (strncmp(line, "COMPOUNDPERMITFLAG", 18) == 0) {
+      if (parse_flag(line, &compoundpermitflag, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag used by compound_check() method */
-    if (line.compare(0, 18, "COMPOUNDFORBIDFLAG", 18) == 0) {
-      if (!parse_flag(line, &compoundforbidflag, afflst)) {
+    if (strncmp(line, "COMPOUNDFORBIDFLAG", 18) == 0) {
+      if (parse_flag(line, &compoundforbidflag, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
-    if (line.compare(0, 20, "COMPOUNDMORESUFFIXES", 20) == 0) {
+    if (strncmp(line, "COMPOUNDMORESUFFIXES", 20) == 0) {
       compoundmoresuffixes = 1;
     }
 
-    if (line.compare(0, 16, "CHECKCOMPOUNDDUP", 16) == 0) {
+    if (strncmp(line, "CHECKCOMPOUNDDUP", 16) == 0) {
       checkcompounddup = 1;
     }
 
-    if (line.compare(0, 16, "CHECKCOMPOUNDREP", 16) == 0) {
+    if (strncmp(line, "CHECKCOMPOUNDREP", 16) == 0) {
       checkcompoundrep = 1;
     }
 
-    if (line.compare(0, 19, "CHECKCOMPOUNDTRIPLE", 19) == 0) {
+    if (strncmp(line, "CHECKCOMPOUNDTRIPLE", 19) == 0) {
       checkcompoundtriple = 1;
     }
 
-    if (line.compare(0, 16, "SIMPLIFIEDTRIPLE", 16) == 0) {
+    if (strncmp(line, "SIMPLIFIEDTRIPLE", 16) == 0) {
       simplifiedtriple = 1;
     }
 
-    if (line.compare(0, 17, "CHECKCOMPOUNDCASE", 17) == 0) {
+    if (strncmp(line, "CHECKCOMPOUNDCASE", 17) == 0) {
       checkcompoundcase = 1;
     }
 
-    if (line.compare(0, 9, "NOSUGGEST", 9) == 0) {
-      if (!parse_flag(line, &nosuggest, afflst)) {
+    if (strncmp(line, "NOSUGGEST", 9) == 0) {
+      if (parse_flag(line, &nosuggest, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
-    if (line.compare(0, 14, "NONGRAMSUGGEST", 14) == 0) {
-      if (!parse_flag(line, &nongramsuggest, afflst)) {
+    if (strncmp(line, "NONGRAMSUGGEST", 14) == 0) {
+      if (parse_flag(line, &nongramsuggest, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag used by forbidden words */
-    if (line.compare(0, 13, "FORBIDDENWORD", 13) == 0) {
-      if (!parse_flag(line, &forbiddenword, afflst)) {
+    if (strncmp(line, "FORBIDDENWORD", 13) == 0) {
+      if (parse_flag(line, &forbiddenword, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag used by forbidden words */
-    if (line.compare(0, 13, "LEMMA_PRESENT", 13) == 0) {
-      if (!parse_flag(line, &lemma_present, afflst)) {
+    if (strncmp(line, "LEMMA_PRESENT", 13) == 0) {
+      if (parse_flag(line, &lemma_present, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag used by circumfixes */
-    if (line.compare(0, 9, "CIRCUMFIX", 9) == 0) {
-      if (!parse_flag(line, &circumfix, afflst)) {
+    if (strncmp(line, "CIRCUMFIX", 9) == 0) {
+      if (parse_flag(line, &circumfix, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag used by fogemorphemes */
-    if (line.compare(0, 14, "ONLYINCOMPOUND", 14) == 0) {
-      if (!parse_flag(line, &onlyincompound, afflst)) {
+    if (strncmp(line, "ONLYINCOMPOUND", 14) == 0) {
+      if (parse_flag(line, &onlyincompound, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag used by `needaffixs' */
-    if (line.compare(0, 10, "PSEUDOROOT", 10) == 0) {
-      if (!parse_flag(line, &needaffix, afflst)) {
+    if (strncmp(line, "PSEUDOROOT", 10) == 0) {
+      if (parse_flag(line, &needaffix, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag used by `needaffixs' */
-    if (line.compare(0, 9, "NEEDAFFIX", 9) == 0) {
-      if (!parse_flag(line, &needaffix, afflst)) {
+    if (strncmp(line, "NEEDAFFIX", 9) == 0) {
+      if (parse_flag(line, &needaffix, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the minimal length for words in compounds */
-    if (line.compare(0, 11, "COMPOUNDMIN", 11) == 0) {
-      if (!parse_num(line, &cpdmin, afflst)) {
+    if (strncmp(line, "COMPOUNDMIN", 11) == 0) {
+      if (parse_num(line, &cpdmin, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
       if (cpdmin < 1)
         cpdmin = 1;
     }
 
     /* parse in the max. words and syllables in compounds */
-    if (line.compare(0, 16, "COMPOUNDSYLLABLE", 16) == 0) {
-      if (!parse_cpdsyllable(line, afflst)) {
+    if (strncmp(line, "COMPOUNDSYLLABLE", 16) == 0) {
+      if (parse_cpdsyllable(line, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag used by compound_check() method */
-    if (line.compare(0, 11, "SYLLABLENUM", 11) == 0) {
-      if (!parse_string(line, cpdsyllablenum, afflst->getlinenum())) {
+    if (strncmp(line, "SYLLABLENUM", 11) == 0) {
+      if (parse_string(line, &cpdsyllablenum, afflst->getlinenum())) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag used by the controlled compound words */
-    if (line.compare(0, 8, "CHECKNUM", 8) == 0) {
+    if (strncmp(line, "CHECKNUM", 8) == 0) {
       checknum = 1;
     }
 
     /* parse in the extra word characters */
-    if (line.compare(0, 9, "WORDCHARS", 9) == 0) {
-      if (!parse_array(line, wordchars, wordchars_utf16,
+    if (strncmp(line, "WORDCHARS", 9) == 0) {
+      if (!parse_array(line, &wordchars, wordchars_utf16,
                        utf8, afflst->getlinenum())) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the ignored characters (for example, Arabic optional diacretics
      * charachters */
-    if (line.compare(0, 6, "IGNORE", 6) == 0) {
-      if (!parse_array(line, ignorechars, ignorechars_utf16,
+    if (strncmp(line, "IGNORE", 6) == 0) {
+      if (!parse_array(line, &ignorechars, ignorechars_utf16,
                        utf8, afflst->getlinenum())) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the typical fault correcting table */
-    if (line.compare(0, 3, "REP", 3) == 0) {
-      if (!parse_reptable(line, afflst)) {
+    if (strncmp(line, "REP", 3) == 0) {
+      if (parse_reptable(line, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the input conversion table */
-    if (line.compare(0, 5, "ICONV", 5) == 0) {
-      if (!parse_convtable(line, afflst, &iconvtable, "ICONV")) {
+    if (strncmp(line, "ICONV", 5) == 0) {
+      if (parse_convtable(line, afflst, &iconvtable, "ICONV")) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the input conversion table */
-    if (line.compare(0, 5, "OCONV", 5) == 0) {
-      if (!parse_convtable(line, afflst, &oconvtable, "OCONV")) {
+    if (strncmp(line, "OCONV", 5) == 0) {
+      if (parse_convtable(line, afflst, &oconvtable, "OCONV")) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the phonetic translation table */
-    if (line.compare(0, 5, "PHONE", 5) == 0) {
-      if (!parse_phonetable(line, afflst)) {
+    if (strncmp(line, "PHONE", 5) == 0) {
+      if (parse_phonetable(line, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the checkcompoundpattern table */
-    if (line.compare(0, 20, "CHECKCOMPOUNDPATTERN", 20) == 0) {
-      if (!parse_checkcpdtable(line, afflst)) {
+    if (strncmp(line, "CHECKCOMPOUNDPATTERN", 20) == 0) {
+      if (parse_checkcpdtable(line, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the defcompound table */
-    if (line.compare(0, 12, "COMPOUNDRULE", 12) == 0) {
-      if (!parse_defcpdtable(line, afflst)) {
+    if (strncmp(line, "COMPOUNDRULE", 12) == 0) {
+      if (parse_defcpdtable(line, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the related character map table */
-    if (line.compare(0, 3, "MAP", 3) == 0) {
-      if (!parse_maptable(line, afflst)) {
+    if (strncmp(line, "MAP", 3) == 0) {
+      if (parse_maptable(line, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the word breakpoints table */
-    if (line.compare(0, 5, "BREAK", 5) == 0) {
-      if (!parse_breaktable(line, afflst)) {
+    if (strncmp(line, "BREAK", 5) == 0) {
+      if (parse_breaktable(line, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the language for language specific codes */
-    if (line.compare(0, 4, "LANG", 4) == 0) {
-      if (!parse_string(line, lang, afflst->getlinenum())) {
+    if (strncmp(line, "LANG", 4) == 0) {
+      if (parse_string(line, &lang, afflst->getlinenum())) {
         finishFileMgr(afflst);
         return 1;
       }
       langnum = get_lang_num(lang);
     }
 
-    if (line.compare(0, 7, "VERSION", 7) == 0) {
-      size_t startpos = line.find_first_not_of(" \t", 7);
-      if (startpos != std::string::npos) {
-          version = line.substr(startpos);
-      }
+    if (strncmp(line, "VERSION", 7) == 0) {
+      for (line = line + 7; *line == ' ' || *line == '\t'; line++)
+        ;
+      version = mystrdup(line);
     }
 
-    if (line.compare(0, 12, "MAXNGRAMSUGS", 12) == 0) {
-      if (!parse_num(line, &maxngramsugs, afflst)) {
+    if (strncmp(line, "MAXNGRAMSUGS", 12) == 0) {
+      if (parse_num(line, &maxngramsugs, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
-    if (line.compare(0, 11, "ONLYMAXDIFF", 11) == 0)
+    if (strncmp(line, "ONLYMAXDIFF", 11) == 0)
       onlymaxdiff = 1;
 
-    if (line.compare(0, 7, "MAXDIFF", 7) == 0) {
-      if (!parse_num(line, &maxdiff, afflst)) {
+    if (strncmp(line, "MAXDIFF", 7) == 0) {
+      if (parse_num(line, &maxdiff, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
-    if (line.compare(0, 10, "MAXCPDSUGS", 10) == 0) {
-      if (!parse_num(line, &maxcpdsugs, afflst)) {
+    if (strncmp(line, "MAXCPDSUGS", 10) == 0) {
+      if (parse_num(line, &maxcpdsugs, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
-    if (line.compare(0, 11, "NOSPLITSUGS", 11) == 0) {
+    if (strncmp(line, "NOSPLITSUGS", 11) == 0) {
       nosplitsugs = 1;
     }
 
-    if (line.compare(0, 9, "FULLSTRIP", 9) == 0) {
+    if (strncmp(line, "FULLSTRIP", 9) == 0) {
       fullstrip = 1;
     }
 
-    if (line.compare(0, 12, "SUGSWITHDOTS", 12) == 0) {
+    if (strncmp(line, "SUGSWITHDOTS", 12) == 0) {
       sugswithdots = 1;
     }
 
     /* parse in the flag used by forbidden words */
-    if (line.compare(0, 8, "KEEPCASE", 8) == 0) {
-      if (!parse_flag(line, &keepcase, afflst)) {
+    if (strncmp(line, "KEEPCASE", 8) == 0) {
+      if (parse_flag(line, &keepcase, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag used by `forceucase' */
-    if (line.compare(0, 10, "FORCEUCASE", 10) == 0) {
-      if (!parse_flag(line, &forceucase, afflst)) {
+    if (strncmp(line, "FORCEUCASE", 10) == 0) {
+      if (parse_flag(line, &forceucase, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag used by `warn' */
-    if (line.compare(0, 4, "WARN", 4) == 0) {
-      if (!parse_flag(line, &warn, afflst)) {
+    if (strncmp(line, "WARN", 4) == 0) {
+      if (parse_flag(line, &warn, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
-    if (line.compare(0, 10, "FORBIDWARN", 10) == 0) {
+    if (strncmp(line, "FORBIDWARN", 10) == 0) {
       forbidwarn = 1;
     }
 
     /* parse in the flag used by the affix generator */
-    if (line.compare(0, 11, "SUBSTANDARD", 11) == 0) {
-      if (!parse_flag(line, &substandard, afflst)) {
+    if (strncmp(line, "SUBSTANDARD", 11) == 0) {
+      if (parse_flag(line, &substandard, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
-    if (line.compare(0, 11, "CHECKSHARPS", 11) == 0) {
+    if (strncmp(line, "CHECKSHARPS", 11) == 0) {
       checksharps = 1;
     }
 
     /* parse this affix: P - prefix, S - suffix */
-    // affix type
-    char ft = ' ';
-    if (line.compare(0, 3, "PFX", 3) == 0)
+    ft = ' ';
+    if (strncmp(line, "PFX", 3) == 0)
       ft = complexprefixes ? 'S' : 'P';
-    if (line.compare(0, 3, "SFX", 3) == 0)
+    if (strncmp(line, "SFX", 3) == 0)
       ft = complexprefixes ? 'P' : 'S';
     if (ft != ' ') {
       if (dupflags_ini) {
         memset(dupflags, 0, sizeof(dupflags));
         dupflags_ini = 0;
       }
-      if (!parse_affix(line, ft, afflst, dupflags)) {
+      if (parse_affix(line, ft, afflst, dupflags)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
   }
 
   finishFileMgr(afflst);
   // affix trees are sorted now
@@ -736,32 +843,47 @@ int AffixMgr::parse_file(const char* aff
   // initialize
   // the nextne and nexteq pointers that relate them
 
   process_pfx_order();
   process_sfx_order();
 
   /* get encoding for CHECKCOMPOUNDCASE */
   if (!utf8) {
-    csconv = get_current_cs(get_encoding());
+    char* enc = get_encoding();
+    csconv = get_current_cs(enc);
+    free(enc);
+    enc = NULL;
+
+    std::string expw;
+    if (wordchars) {
+      expw.assign(wordchars);
+      free(wordchars);
+    }
+
     for (int i = 0; i <= 255; i++) {
       if ((csconv[i].cupper != csconv[i].clower) &&
-          (wordchars.find((char)i) == std::string::npos)) {
-        wordchars.push_back((char)i);
+          (expw.find((char)i) == std::string::npos)) {
+        expw.push_back((char)i);
       }
     }
 
+    wordchars = mystrdup(expw.c_str());
   }
 
   // default BREAK definition
-  if (!parsedbreaktable) {
-    breaktable.push_back("-");
-    breaktable.push_back("^-");
-    breaktable.push_back("-$");
-    parsedbreaktable = true;
+  if (numbreak == -1) {
+    breaktable = (char**)malloc(sizeof(char*) * 3);
+    if (!breaktable)
+      return 1;
+    breaktable[0] = mystrdup("-");
+    breaktable[1] = mystrdup("^-");
+    breaktable[2] = mystrdup("-$");
+    if (breaktable[0] && breaktable[1] && breaktable[2])
+      numbreak = 3;
   }
   return 0;
 }
 
 // we want to be able to quickly access prefix information
 // both by prefix flag, and sorted by prefix string itself
 // so we need to set up two indexes
 
@@ -822,19 +944,16 @@ int AffixMgr::build_pfxtree(PfxEntry* pf
   }
   return 0;
 }
 
 // we want to be able to quickly access suffix information
 // both by suffix flag, and sorted by the reverse of the
 // suffix string itself; so we need to set up two indexes
 int AffixMgr::build_sfxtree(SfxEntry* sfxptr) {
-
-  sfxptr->initReverseWord();
-
   SfxEntry* ptr;
   SfxEntry* pptr;
   SfxEntry* ep = sfxptr;
 
   /* get the right starting point */
   const char* key = ep->getKey();
   const unsigned char flg = (unsigned char)(ep->getFlag() & 0x00FF);
 
@@ -1019,16 +1138,27 @@ int AffixMgr::process_sfx_order() {
       if (mptr)
         mptr->setNextNE(NULL);
     }
   }
   return 0;
 }
 
 // add flags to the result for dictionary debugging
+void AffixMgr::debugflag(char* result, unsigned short flag) {
+  char* st = encode_flag(flag);
+  mystrcat(result, " ", MAXLNLEN);
+  mystrcat(result, MORPH_FLAG, MAXLNLEN);
+  if (st) {
+    mystrcat(result, st, MAXLNLEN);
+    free(st);
+  }
+}
+
+// add flags to the result for dictionary debugging
 std::string& AffixMgr::debugflag(std::string& result, unsigned short flag) {
   char* st = encode_flag(flag);
   result.append(" ");
   result.append(MORPH_FLAG);
   if (st) {
     result.append(st);
     free(st);
   }
@@ -1046,28 +1176,23 @@ int AffixMgr::condlen(const char* st) {
     } else if (*st == ']')
       group = false;
     else if (!group && (!utf8 || (!(*st & 0x80) || ((*st & 0xc0) == 0x80))))
       l++;
   }
   return l;
 }
 
-int AffixMgr::encodeit(AffEntry& entry, const char* cs) {
+int AffixMgr::encodeit(affentry& entry, const char* cs) {
   if (strcmp(cs, ".") != 0) {
     entry.numconds = (char)condlen(cs);
-    const size_t cslen = strlen(cs);
-    const size_t short_part = std::min<size_t>(MAXCONDLEN, cslen);
-    memcpy(entry.c.conds, cs, short_part);
-    if (short_part < MAXCONDLEN) {
-      //blank out the remaining space
-      memset(entry.c.conds + short_part, 0, MAXCONDLEN - short_part);
-    } else if (cs[MAXCONDLEN]) {
-      //there is more conditions than fit in fixed space, so its
-      //a long condition
+    // coverity[buffer_size_warning] - deliberate use of lack of end of conds
+    // padded by strncpy as long condition flag
+    strncpy(entry.c.conds, cs, MAXCONDLEN);
+    if (entry.c.conds[MAXCONDLEN - 1] && cs[MAXCONDLEN]) {
       entry.opts += aeLONGCOND;
       entry.c.l.conds2 = mystrdup(cs + MAXCONDLEN_1);
       if (!entry.c.l.conds2)
         return 1;
     }
   } else {
     entry.numconds = 0;
     entry.c.conds[0] = '\0';
@@ -1186,149 +1311,156 @@ struct hentry* AffixMgr::prefix_check_tw
       pptr = pptr->getNextNE();
     }
   }
 
   return NULL;
 }
 
 // check word for prefixes
-std::string AffixMgr::prefix_check_morph(const char* word,
-                                         int len,
-                                         char in_compound,
-                                         const FLAG needflag) {
-
-  std::string result;
+char* AffixMgr::prefix_check_morph(const char* word,
+                                   int len,
+                                   char in_compound,
+                                   const FLAG needflag) {
+
+  char result[MAXLNLEN];
+  result[0] = '\0';
 
   pfx = NULL;
   sfxappnd = NULL;
   sfxextra = 0;
 
   // first handle the special case of 0 length prefixes
   PfxEntry* pe = pStart[0];
   while (pe) {
-    std::string st = pe->check_morph(word, len, in_compound, needflag);
-    if (!st.empty()) {
-      result.append(st);
+    char* st = pe->check_morph(word, len, in_compound, needflag);
+    if (st) {
+      mystrcat(result, st, MAXLNLEN);
+      free(st);
+    }
+    // if (rv) return rv;
+    pe = pe->getNext();
+  }
+
+  // now handle the general case
+  unsigned char sp = *((const unsigned char*)word);
+  PfxEntry* pptr = pStart[sp];
+
+  while (pptr) {
+    if (isSubset(pptr->getKey(), word)) {
+      char* st = pptr->check_morph(word, len, in_compound, needflag);
+      if (st) {
+        // fogemorpheme
+        if ((in_compound != IN_CPD_NOT) ||
+            !((pptr->getCont() && (TESTAFF(pptr->getCont(), onlyincompound,
+                                           pptr->getContLen()))))) {
+          mystrcat(result, st, MAXLNLEN);
+          pfx = pptr;
+        }
+        free(st);
+      }
+      pptr = pptr->getNextEQ();
+    } else {
+      pptr = pptr->getNextNE();
+    }
+  }
+
+  if (*result)
+    return mystrdup(result);
+  return NULL;
+}
+
+// check word for prefixes
+char* AffixMgr::prefix_check_twosfx_morph(const char* word,
+                                          int len,
+                                          char in_compound,
+                                          const FLAG needflag) {
+  char result[MAXLNLEN];
+  result[0] = '\0';
+
+  pfx = NULL;
+  sfxappnd = NULL;
+  sfxextra = 0;
+
+  // first handle the special case of 0 length prefixes
+  PfxEntry* pe = pStart[0];
+  while (pe) {
+    char* st = pe->check_twosfx_morph(word, len, in_compound, needflag);
+    if (st) {
+      mystrcat(result, st, MAXLNLEN);
+      free(st);
     }
     pe = pe->getNext();
   }
 
   // now handle the general case
   unsigned char sp = *((const unsigned char*)word);
   PfxEntry* pptr = pStart[sp];
 
   while (pptr) {
     if (isSubset(pptr->getKey(), word)) {
-      std::string st = pptr->check_morph(word, len, in_compound, needflag);
-      if (!st.empty()) {
-        // fogemorpheme
-        if ((in_compound != IN_CPD_NOT) ||
-            !((pptr->getCont() && (TESTAFF(pptr->getCont(), onlyincompound,
-                                           pptr->getContLen()))))) {
-          result.append(st);
-          pfx = pptr;
-        }
-      }
-      pptr = pptr->getNextEQ();
-    } else {
-      pptr = pptr->getNextNE();
-    }
-  }
-
-  return result;
-}
-
-// check word for prefixes
-std::string AffixMgr::prefix_check_twosfx_morph(const char* word,
-                                                int len,
-                                                char in_compound,
-                                                const FLAG needflag) {
-  std::string result;
-
-  pfx = NULL;
-  sfxappnd = NULL;
-  sfxextra = 0;
-
-  // first handle the special case of 0 length prefixes
-  PfxEntry* pe = pStart[0];
-  while (pe) {
-    std::string st = pe->check_twosfx_morph(word, len, in_compound, needflag);
-    if (!st.empty()) {
-      result.append(st);
-    }
-    pe = pe->getNext();
-  }
-
-  // now handle the general case
-  unsigned char sp = *((const unsigned char*)word);
-  PfxEntry* pptr = pStart[sp];
-
-  while (pptr) {
-    if (isSubset(pptr->getKey(), word)) {
-      std::string st = pptr->check_twosfx_morph(word, len, in_compound, needflag);
-      if (!st.empty()) {
-        result.append(st);
+      char* st = pptr->check_twosfx_morph(word, len, in_compound, needflag);
+      if (st) {
+        mystrcat(result, st, MAXLNLEN);
+        free(st);
         pfx = pptr;
       }
       pptr = pptr->getNextEQ();
     } else {
       pptr = pptr->getNextNE();
     }
   }
 
-  return result;
+  if (*result)
+    return mystrdup(result);
+  return NULL;
 }
 
 // Is word a non compound with a REP substitution (see checkcompoundrep)?
 int AffixMgr::cpdrep_check(const char* word, int wl) {
 
-  if ((wl < 2) || reptable.empty())
+  if ((wl < 2) || !numrep)
     return 0;
 
-  for (size_t i = 0; i < reptable.size(); ++i) {
+  for (int i = 0; i < numrep; i++) {
     const char* r = word;
-    const size_t lenp = reptable[i].pattern.size();
+    int lenp = strlen(reptable[i].pattern);
     // search every occurence of the pattern in the word
-    while ((r = strstr(r, reptable[i].pattern.c_str())) != NULL) {
+    while ((r = strstr(r, reptable[i].pattern)) != NULL) {
       std::string candidate(word);
-      size_t type = r == word ? 1 : 0;
-      if (r - word + reptable[i].pattern.size() == lenp)
-        type += 2;
-      candidate.replace(r - word, lenp, reptable[i].outstrings[type]);
+      candidate.replace(r - word, lenp, reptable[i].pattern2);
       if (candidate_check(candidate.c_str(), candidate.size()))
         return 1;
-      ++r;  // search for the next letter
+      r++;  // search for the next letter
     }
   }
-
   return 0;
 }
 
 // forbid compoundings when there are special patterns at word bound
 int AffixMgr::cpdpat_check(const char* word,
                            int pos,
                            hentry* r1,
                            hentry* r2,
                            const char /*affixed*/) {
-  for (size_t i = 0; i < checkcpdtable.size(); ++i) {
-    size_t len;
-    if (isSubset(checkcpdtable[i].pattern2.c_str(), word + pos) &&
+  int len;
+  for (int i = 0; i < numcheckcpd; i++) {
+    if (isSubset(checkcpdtable[i].pattern2, word + pos) &&
         (!r1 || !checkcpdtable[i].cond ||
          (r1->astr && TESTAFF(r1->astr, checkcpdtable[i].cond, r1->alen))) &&
         (!r2 || !checkcpdtable[i].cond2 ||
          (r2->astr && TESTAFF(r2->astr, checkcpdtable[i].cond2, r2->alen))) &&
         // zero length pattern => only TESTAFF
         // zero pattern (0/flag) => unmodified stem (zero affixes allowed)
-        (checkcpdtable[i].pattern.empty() ||
-         ((checkcpdtable[i].pattern[0] == '0' && r1->blen <= pos &&
+        (!*(checkcpdtable[i].pattern) ||
+         ((*(checkcpdtable[i].pattern) == '0' && r1->blen <= pos &&
            strncmp(word + pos - r1->blen, r1->word, r1->blen) == 0) ||
-          (checkcpdtable[i].pattern[0] != '0' &&
-           ((len = checkcpdtable[i].pattern.size()) != 0) &&
-           strncmp(word + pos - len, checkcpdtable[i].pattern.c_str(), len) == 0)))) {
+          (*(checkcpdtable[i].pattern) != '0' &&
+           ((len = strlen(checkcpdtable[i].pattern)) != 0) &&
+           strncmp(word + pos - len, checkcpdtable[i].pattern, len) == 0)))) {
       return 1;
     }
   }
   return 0;
 }
 
 // forbid compounding with neighbouring upper and lower case characters at word
 // bounds
@@ -1376,62 +1508,63 @@ int AffixMgr::defcpd_check(hentry*** wor
 
   if (!*words) {
     return 0;
   }
 
   std::vector<metachar_data> btinfo(1);
 
   short bt = 0;
+  int i, j;
 
   (*words)[wnum] = rv;
 
   // has the last word COMPOUNDRULE flag?
   if (rv->alen == 0) {
     (*words)[wnum] = NULL;
     if (w)
       *words = NULL;
     return 0;
   }
   int ok = 0;
-  for (size_t i = 0; i < defcpdtable.size(); ++i) {
-    for (size_t j = 0; j < defcpdtable[i].size(); ++j) {
-      if (defcpdtable[i][j] != '*' && defcpdtable[i][j] != '?' &&
-          TESTAFF(rv->astr, defcpdtable[i][j], rv->alen)) {
+  for (i = 0; i < numdefcpd; i++) {
+    for (j = 0; j < defcpdtable[i].len; j++) {
+      if (defcpdtable[i].def[j] != '*' && defcpdtable[i].def[j] != '?' &&
+          TESTAFF(rv->astr, defcpdtable[i].def[j], rv->alen)) {
         ok = 1;
         break;
       }
     }
   }
   if (ok == 0) {
     (*words)[wnum] = NULL;
     if (w)
       *words = NULL;
     return 0;
   }
 
-  for (size_t i = 0; i < defcpdtable.size(); ++i) {
-    size_t pp = 0;  // pattern position
+  for (i = 0; i < numdefcpd; i++) {
+    signed short pp = 0;  // pattern position
     signed short wp = 0;  // "words" position
     int ok2;
     ok = 1;
     ok2 = 1;
     do {
-      while ((pp < defcpdtable[i].size()) && (wp <= wnum)) {
-        if (((pp + 1) < defcpdtable[i].size()) &&
-            ((defcpdtable[i][pp + 1] == '*') ||
-             (defcpdtable[i][pp + 1] == '?'))) {
-          int wend = (defcpdtable[i][pp + 1] == '?') ? wp : wnum;
+      while ((pp < defcpdtable[i].len) && (wp <= wnum)) {
+        if (((pp + 1) < defcpdtable[i].len) &&
+            ((defcpdtable[i].def[pp + 1] == '*') ||
+             (defcpdtable[i].def[pp + 1] == '?'))) {
+          int wend = (defcpdtable[i].def[pp + 1] == '?') ? wp : wnum;
           ok2 = 1;
           pp += 2;
           btinfo[bt].btpp = pp;
           btinfo[bt].btwp = wp;
           while (wp <= wend) {
             if (!(*words)[wp]->alen ||
-                !TESTAFF((*words)[wp]->astr, defcpdtable[i][pp - 2],
+                !TESTAFF((*words)[wp]->astr, defcpdtable[i].def[pp - 2],
                          (*words)[wp]->alen)) {
               ok2 = 0;
               break;
             }
             wp++;
           }
           if (wp <= wnum)
             ok2 = 0;
@@ -1440,56 +1573,56 @@ int AffixMgr::defcpd_check(hentry*** wor
             ++bt;
             btinfo.resize(bt+1);
           }
           if (ok2)
             break;
         } else {
           ok2 = 1;
           if (!(*words)[wp] || !(*words)[wp]->alen ||
-              !TESTAFF((*words)[wp]->astr, defcpdtable[i][pp],
+              !TESTAFF((*words)[wp]->astr, defcpdtable[i].def[pp],
                        (*words)[wp]->alen)) {
             ok = 0;
             break;
           }
           pp++;
           wp++;
-          if ((defcpdtable[i].size() == pp) && !(wp > wnum))
+          if ((defcpdtable[i].len == pp) && !(wp > wnum))
             ok = 0;
         }
       }
       if (ok && ok2) {
-        size_t r = pp;
-        while ((defcpdtable[i].size() > r) && ((r + 1) < defcpdtable[i].size()) &&
-               ((defcpdtable[i][r + 1] == '*') ||
-                (defcpdtable[i][r + 1] == '?')))
+        int r = pp;
+        while ((defcpdtable[i].len > r) && ((r + 1) < defcpdtable[i].len) &&
+               ((defcpdtable[i].def[r + 1] == '*') ||
+                (defcpdtable[i].def[r + 1] == '?')))
           r += 2;
-        if (defcpdtable[i].size() <= r)
+        if (defcpdtable[i].len <= r)
           return 1;
       }
       // backtrack
       if (bt)
         do {
           ok = 1;
           btinfo[bt - 1].btnum--;
           pp = btinfo[bt - 1].btpp;
           wp = btinfo[bt - 1].btwp + (signed short)btinfo[bt - 1].btnum;
         } while ((btinfo[bt - 1].btnum < 0) && --bt);
     } while (bt);
 
-    if (ok && ok2 && (!all || (defcpdtable[i].size() <= pp)))
+    if (ok && ok2 && (!all || (defcpdtable[i].len <= pp)))
       return 1;
 
     // check zero ending
-    while (ok && ok2 && (defcpdtable[i].size() > pp) &&
-           ((pp + 1) < defcpdtable[i].size()) &&
-           ((defcpdtable[i][pp + 1] == '*') ||
-            (defcpdtable[i][pp + 1] == '?')))
+    while (ok && ok2 && (defcpdtable[i].len > pp) &&
+           ((pp + 1) < defcpdtable[i].len) &&
+           ((defcpdtable[i].def[pp + 1] == '*') ||
+            (defcpdtable[i].def[pp + 1] == '?')))
       pp += 2;
-    if (ok && ok2 && (defcpdtable[i].size() <= pp))
+    if (ok && ok2 && (defcpdtable[i].len <= pp))
       return 1;
   }
   (*words)[wnum] = NULL;
   if (w)
     *words = NULL;
   return 0;
 }
 
@@ -1513,33 +1646,30 @@ inline int AffixMgr::candidate_check(con
 short AffixMgr::get_syllable(const std::string& word) {
   if (cpdmaxsyllable == 0)
     return 0;
 
   short num = 0;
 
   if (!utf8) {
     for (size_t i = 0; i < word.size(); ++i) {
-      if (std::binary_search(cpdvowels.begin(), cpdvowels.end(),
-                             word[i])) {
-        ++num;
-      }
+      if (strchr(cpdvowels, word[i]))
+        num++;
     }
-  } else if (!cpdvowels_utf16.empty()) {
+  } else if (cpdvowels_utf16) {
     std::vector<w_char> w;
-    u8_u16(w, word);
-    for (size_t i = 0; i < w.size(); ++i) {
-      if (std::binary_search(cpdvowels_utf16.begin(),
-                             cpdvowels_utf16.end(),
-                             w[i])) {
+    int i = u8_u16(w, word);
+    for (; i > 0; i--) {
+      if (std::binary_search(cpdvowels_utf16,
+                             cpdvowels_utf16 + cpdvowels_utf16_len,
+                             w[i - 1])) {
         ++num;
       }
     }
   }
-
   return num;
 }
 
 void AffixMgr::setcminmax(int* cmin, int* cmax, const char* word, int len) {
   if (utf8) {
     int i;
     for (*cmin = 0, i = 0; (i < cpdmin) && *cmin < len; i++) {
       for ((*cmin)++; *cmin < len && (word[*cmin] & 0xc0) == 0x80; (*cmin)++)
@@ -1552,17 +1682,18 @@ void AffixMgr::setcminmax(int* cmin, int
   } else {
     *cmin = cpdmin;
     *cmax = len - cpdmin + 1;
   }
 }
 
 // check if compound word is correctly spelled
 // hu_mov_rule = spec. Hungarian rule (XXX)
-struct hentry* AffixMgr::compound_check(const std::string& word,
+struct hentry* AffixMgr::compound_check(const char* word,
+                                        int len,
                                         short wordnum,
                                         short numsyllable,
                                         short maxwordnum,
                                         short wnum,
                                         hentry** words = NULL,
                                         hentry** rwords = NULL,
                                         char hu_mov_rule = 0,
                                         char is_sug = 0,
@@ -1571,73 +1702,73 @@ struct hentry* AffixMgr::compound_check(
   short oldnumsyllable, oldnumsyllable2, oldwordnum, oldwordnum2;
   struct hentry* rv = NULL;
   struct hentry* rv_first;
   std::string st;
   char ch = '\0';
   int cmin;
   int cmax;
   int striple = 0;
-  size_t scpd = 0;
+  int scpd = 0;
   int soldi = 0;
   int oldcmin = 0;
   int oldcmax = 0;
   int oldlen = 0;
   int checkedstriple = 0;
+  int onlycpdrule;
   char affixed = 0;
   hentry** oldwords = words;
-  size_t len = word.size();
 
   int checked_prefix;
 
-  setcminmax(&cmin, &cmax, word.c_str(), len);
+  setcminmax(&cmin, &cmax, word, len);
 
   st.assign(word);
 
   for (i = cmin; i < cmax; i++) {
     // go to end of the UTF-8 character
     if (utf8) {
       for (; (st[i] & 0xc0) == 0x80; i++)
         ;
       if (i >= cmax)
         return NULL;
     }
 
     words = oldwords;
-    int onlycpdrule = (words) ? 1 : 0;
+    onlycpdrule = (words) ? 1 : 0;
 
     do {  // onlycpdrule loop
 
       oldnumsyllable = numsyllable;
       oldwordnum = wordnum;
       checked_prefix = 0;
 
       do {  // simplified checkcompoundpattern loop
 
         if (scpd > 0) {
-          for (; scpd <= checkcpdtable.size() &&
-                 (checkcpdtable[scpd - 1].pattern3.empty() ||
-                  strncmp(word.c_str() + i, checkcpdtable[scpd - 1].pattern3.c_str(),
-                          checkcpdtable[scpd - 1].pattern3.size()) != 0);
+          for (; scpd <= numcheckcpd &&
+                 (!checkcpdtable[scpd - 1].pattern3 ||
+                  strncmp(word + i, checkcpdtable[scpd - 1].pattern3,
+                          strlen(checkcpdtable[scpd - 1].pattern3)) != 0);
                scpd++)
             ;
 
-          if (scpd > checkcpdtable.size())
+          if (scpd > numcheckcpd)
             break;  // break simplified checkcompoundpattern loop
           st.replace(i, std::string::npos, checkcpdtable[scpd - 1].pattern);
           soldi = i;
-          i += checkcpdtable[scpd - 1].pattern.size();
+          i += strlen(checkcpdtable[scpd - 1].pattern);
           st.replace(i, std::string::npos, checkcpdtable[scpd - 1].pattern2);
-          st.replace(i + checkcpdtable[scpd - 1].pattern2.size(), std::string::npos,
-                 word.substr(soldi + checkcpdtable[scpd - 1].pattern3.size()));
+          st.replace(i + strlen(checkcpdtable[scpd - 1].pattern2), std::string::npos,
+                 word + soldi + strlen(checkcpdtable[scpd - 1].pattern3));
 
           oldlen = len;
-          len += checkcpdtable[scpd - 1].pattern.size() +
-                 checkcpdtable[scpd - 1].pattern2.size() -
-                 checkcpdtable[scpd - 1].pattern3.size();
+          len += strlen(checkcpdtable[scpd - 1].pattern) +
+                 strlen(checkcpdtable[scpd - 1].pattern2) -
+                 strlen(checkcpdtable[scpd - 1].pattern3);
           oldcmin = cmin;
           oldcmax = cmax;
           setcminmax(&cmin, &cmax, st.c_str(), len);
 
           cmax = len - cpdmin + 1;
         }
 
         ch = st[i];
@@ -1655,17 +1786,17 @@ struct hentry* AffixMgr::compound_check(
         while ((rv) && !hu_mov_rule &&
                ((needaffix && TESTAFF(rv->astr, needaffix, rv->alen)) ||
                 !((compoundflag && !words && !onlycpdrule &&
                    TESTAFF(rv->astr, compoundflag, rv->alen)) ||
                   (compoundbegin && !wordnum && !onlycpdrule &&
                    TESTAFF(rv->astr, compoundbegin, rv->alen)) ||
                   (compoundmiddle && wordnum && !words && !onlycpdrule &&
                    TESTAFF(rv->astr, compoundmiddle, rv->alen)) ||
-                  (!defcpdtable.empty() && onlycpdrule &&
+                  (numdefcpd && onlycpdrule &&
                    ((!words && !wordnum &&
                      defcpd_check(&words, wnum, rv, rwords, 0)) ||
                     (words &&
                      defcpd_check(&words, wnum, rv, rwords, 0))))) ||
                 (scpd != 0 && checkcpdtable[scpd - 1].cond != FLAG_NULL &&
                  !TESTAFF(rv->astr, checkcpdtable[scpd - 1].cond, rv->alen)))) {
           rv = rv->next_homonym;
         }
@@ -1676,45 +1807,45 @@ struct hentry* AffixMgr::compound_check(
         if (!rv) {
           if (onlycpdrule)
             break;
           if (compoundflag &&
               !(rv = prefix_check(st.c_str(), i,
                                   hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN,
                                   compoundflag))) {
             if (((rv = suffix_check(
-                      st.c_str(), i, 0, NULL, FLAG_NULL, compoundflag,
+                      st.c_str(), i, 0, NULL, NULL, 0, NULL, FLAG_NULL, compoundflag,
                       hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) ||
                  (compoundmoresuffixes &&
                   (rv = suffix_check_twosfx(st.c_str(), i, 0, NULL, compoundflag)))) &&
                 !hu_mov_rule && sfx->getCont() &&
                 ((compoundforbidflag &&
                   TESTAFF(sfx->getCont(), compoundforbidflag,
                           sfx->getContLen())) ||
                  (compoundend &&
                   TESTAFF(sfx->getCont(), compoundend, sfx->getContLen())))) {
               rv = NULL;
             }
           }
 
           if (rv ||
               (((wordnum == 0) && compoundbegin &&
                 ((rv = suffix_check(
-                      st.c_str(), i, 0, NULL, FLAG_NULL, compoundbegin,
+                      st.c_str(), i, 0, NULL, NULL, 0, NULL, FLAG_NULL, compoundbegin,
                       hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) ||
                  (compoundmoresuffixes &&
                   (rv = suffix_check_twosfx(
                        st.c_str(), i, 0, NULL,
                        compoundbegin))) ||  // twofold suffixes + compound
                  (rv = prefix_check(st.c_str(), i,
                                     hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN,
                                     compoundbegin)))) ||
                ((wordnum > 0) && compoundmiddle &&
                 ((rv = suffix_check(
-                      st.c_str(), i, 0, NULL, FLAG_NULL, compoundmiddle,
+                      st.c_str(), i, 0, NULL, NULL, 0, NULL, FLAG_NULL, compoundmiddle,
                       hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) ||
                  (compoundmoresuffixes &&
                   (rv = suffix_check_twosfx(
                        st.c_str(), i, 0, NULL,
                        compoundmiddle))) ||  // twofold suffixes + compound
                  (rv = prefix_check(st.c_str(), i,
                                     hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN,
                                     compoundmiddle))))))
@@ -1775,17 +1906,18 @@ struct hentry* AffixMgr::compound_check(
 
         // first word is acceptable in compound words?
         if (((rv) &&
              (checked_prefix || (words && words[wnum]) ||
               (compoundflag && TESTAFF(rv->astr, compoundflag, rv->alen)) ||
               ((oldwordnum == 0) && compoundbegin &&
                TESTAFF(rv->astr, compoundbegin, rv->alen)) ||
               ((oldwordnum > 0) && compoundmiddle &&
-               TESTAFF(rv->astr, compoundmiddle, rv->alen))
+               TESTAFF(rv->astr, compoundmiddle, rv->alen))  // ||
+              //            (numdefcpd && )
 
               // LANG_hu section: spec. Hungarian rule
               || ((langnum == LANG_hu) && hu_mov_rule &&
                   (TESTAFF(
                        rv->astr, 'F',
                        rv->alen) ||  // XXX hardwired Hungarian dictionary codes
                    TESTAFF(rv->astr, 'G', rv->alen) ||
                    TESTAFF(rv->astr, 'H', rv->alen)))
@@ -1797,17 +1929,17 @@ struct hentry* AffixMgr::compound_check(
                  TESTAFF(rv->astr, checkcpdtable[scpd - 1].cond, rv->alen)) &&
              !((checkcompoundtriple && scpd == 0 &&
                 !words &&  // test triple letters
                 (word[i - 1] == word[i]) &&
                 (((i > 1) && (word[i - 1] == word[i - 2])) ||
                  ((word[i - 1] == word[i + 1]))  // may be word[i+1] == '\0'
                  )) ||
                (checkcompoundcase && scpd == 0 && !words &&
-                cpdcase_check(word.c_str(), i))))
+                cpdcase_check(word, i))))
             // LANG_hu section: spec. Hungarian rule
             || ((!rv) && (langnum == LANG_hu) && hu_mov_rule &&
                 (rv = affix_check(st.c_str(), i)) &&
                 (sfx && sfx->getCont() &&
                  (  // XXX hardwired Hungarian dic. codes
                      TESTAFF(sfx->getCont(), (unsigned short)'x',
                              sfx->getContLen()) ||
                      TESTAFF(
@@ -1831,30 +1963,30 @@ struct hentry* AffixMgr::compound_check(
 
           do {  // striple loop
 
             // check simplifiedtriple
             if (simplifiedtriple) {
               if (striple) {
                 checkedstriple = 1;
                 i--;  // check "fahrt" instead of "ahrt" in "Schiffahrt"
-              } else if (i > 2 && word[i - 1] == word[i - 2])
+              } else if (i > 2 && *(word + i - 1) == *(word + i - 2))
                 striple = 1;
             }
 
             rv = lookup(st.c_str() + i);  // perhaps without prefix
 
             // search homonym with compound flag
             while ((rv) &&
                    ((needaffix && TESTAFF(rv->astr, needaffix, rv->alen)) ||
                     !((compoundflag && !words &&
                        TESTAFF(rv->astr, compoundflag, rv->alen)) ||
                       (compoundend && !words &&
                        TESTAFF(rv->astr, compoundend, rv->alen)) ||
-                      (!defcpdtable.empty() && words &&
+                      (numdefcpd && words &&
                        defcpd_check(&words, wnum + 1, rv, NULL, 1))) ||
                     (scpd != 0 && checkcpdtable[scpd - 1].cond2 != FLAG_NULL &&
                      !TESTAFF(rv->astr, checkcpdtable[scpd - 1].cond2,
                               rv->alen)))) {
               rv = rv->next_homonym;
             }
 
             // check FORCEUCASE
@@ -1901,63 +2033,63 @@ struct hentry* AffixMgr::compound_check(
                 ((compoundflag && TESTAFF(rv->astr, compoundflag, rv->alen)) ||
                  (compoundend && TESTAFF(rv->astr, compoundend, rv->alen))) &&
                 (((cpdwordmax == -1) || (wordnum + 1 < cpdwordmax)) ||
                  ((cpdmaxsyllable != 0) &&
                   (numsyllable + get_syllable(std::string(HENTRY_WORD(rv), rv->clen)) <=
                    cpdmaxsyllable))) &&
                 (
                     // test CHECKCOMPOUNDPATTERN
-                    checkcpdtable.empty() || scpd != 0 ||
-                    !cpdpat_check(word.c_str(), i, rv_first, rv, 0)) &&
+                    !numcheckcpd || scpd != 0 ||
+                    !cpdpat_check(word, i, rv_first, rv, 0)) &&
                 ((!checkcompounddup || (rv != rv_first)))
                 // test CHECKCOMPOUNDPATTERN conditions
                 &&
                 (scpd == 0 || checkcpdtable[scpd - 1].cond2 == FLAG_NULL ||
                  TESTAFF(rv->astr, checkcpdtable[scpd - 1].cond2, rv->alen))) {
               // forbid compound word, if it is a non compound word with typical
               // fault
-              if (checkcompoundrep && cpdrep_check(word.c_str(), len))
+              if (checkcompoundrep && cpdrep_check(word, len))
                 return NULL;
               return rv_first;
             }
 
             numsyllable = oldnumsyllable2;
             wordnum = oldwordnum2;
 
             // perhaps second word has prefix or/and suffix
             sfx = NULL;
             sfxflag = FLAG_NULL;
             rv = (compoundflag && !onlycpdrule)
-                     ? affix_check((word.c_str() + i), strlen(word.c_str() + i), compoundflag,
+                     ? affix_check((word + i), strlen(word + i), compoundflag,
                                    IN_CPD_END)
                      : NULL;
             if (!rv && compoundend && !onlycpdrule) {
               sfx = NULL;
               pfx = NULL;
-              rv = affix_check((word.c_str() + i), strlen(word.c_str() + i), compoundend,
+              rv = affix_check((word + i), strlen(word + i), compoundend,
                                IN_CPD_END);
             }
 
-            if (!rv && !defcpdtable.empty() && words) {
-              rv = affix_check((word.c_str() + i), strlen(word.c_str() + i), 0, IN_CPD_END);
+            if (!rv && numdefcpd && words) {
+              rv = affix_check((word + i), strlen(word + i), 0, IN_CPD_END);
               if (rv && defcpd_check(&words, wnum + 1, rv, NULL, 1))
                 return rv_first;
               rv = NULL;
             }
 
             // test CHECKCOMPOUNDPATTERN conditions (allowed forms)
             if (rv &&
                 !(scpd == 0 || checkcpdtable[scpd - 1].cond2 == FLAG_NULL ||
                   TESTAFF(rv->astr, checkcpdtable[scpd - 1].cond2, rv->alen)))
               rv = NULL;
 
             // test CHECKCOMPOUNDPATTERN conditions (forbidden compounds)
-            if (rv && !checkcpdtable.empty() && scpd == 0 &&
-                cpdpat_check(word.c_str(), i, rv_first, rv, affixed))
+            if (rv && numcheckcpd && scpd == 0 &&
+                cpdpat_check(word, i, rv_first, rv, affixed))
               rv = NULL;
 
             // check non_compound flag in suffix and prefix
             if ((rv) && ((pfx && pfx->getCont() &&
                           TESTAFF(pfx->getCont(), compoundforbidflag,
                                   pfx->getContLen())) ||
                          (sfx && sfx->getCont() &&
                           TESTAFF(sfx->getCont(), compoundforbidflag,
@@ -1981,17 +2113,17 @@ struct hentry* AffixMgr::compound_check(
 
             // pfxappnd = prefix of word+i, or NULL
             // calculate syllable number of prefix.
             // hungarian convention: when syllable number of prefix is more,
             // than 1, the prefix+word counts as two words.
 
             if (langnum == LANG_hu) {
               // calculate syllable number of the word
-              numsyllable += get_syllable(word.c_str() + i);
+              numsyllable += get_syllable(word + i);
 
               // - affix syllable num.
               // XXX only second suffix (inflections, not derivations)
               if (sfxappnd) {
                 std::string tmp(sfxappnd);
                 reverseword(tmp);
                 numsyllable -= get_syllable(tmp) + sfxextra;
               }
@@ -1999,17 +2131,17 @@ struct hentry* AffixMgr::compound_check(
               // + 1 word, if syllable number of the prefix > 1 (hungarian
               // convention)
               if (pfx && (get_syllable(pfx->getKey()) > 1))
                 wordnum++;
 
               // increment syllable num, if last word has a SYLLABLENUM flag
               // and the suffix is beginning `s'
 
-              if (!cpdsyllablenum.empty()) {
+              if (cpdsyllablenum) {
                 switch (sfxflag) {
                   case 'c': {
                     numsyllable += 2;
                     break;
                   }
                   case 'J': {
                     numsyllable += 1;
                     break;
@@ -2034,61 +2166,62 @@ struct hentry* AffixMgr::compound_check(
             // when compound forms consist 2 word, otherwise
             // the syllable number of root words is 6, or lesser.
             if ((rv) &&
                 (((cpdwordmax == -1) || (wordnum + 1 < cpdwordmax)) ||
                  ((cpdmaxsyllable != 0) && (numsyllable <= cpdmaxsyllable))) &&
                 ((!checkcompounddup || (rv != rv_first)))) {
               // forbid compound word, if it is a non compound word with typical
               // fault
-              if (checkcompoundrep && cpdrep_check(word.c_str(), len))
+              if (checkcompoundrep && cpdrep_check(word, len))
                 return NULL;
               return rv_first;
             }
 
             numsyllable = oldnumsyllable2;
             wordnum = oldwordnum2;
 
             // perhaps second word is a compound word (recursive call)
             if (wordnum < maxwordnum) {
-              rv = compound_check(st.substr(i), wordnum + 1,
+              rv = compound_check(st.c_str() + i, strlen(st.c_str() + i), wordnum + 1,
                                   numsyllable, maxwordnum, wnum + 1, words, rwords, 0,
                                   is_sug, info);
 
-              if (rv && !checkcpdtable.empty() &&
+              if (rv && numcheckcpd &&
                   ((scpd == 0 &&
-                    cpdpat_check(word.c_str(), i, rv_first, rv, affixed)) ||
+                    cpdpat_check(word, i, rv_first, rv, affixed)) ||
                    (scpd != 0 &&
-                    !cpdpat_check(word.c_str(), i, rv_first, rv, affixed))))
+                    !cpdpat_check(word, i, rv_first, rv, affixed))))
                 rv = NULL;
             } else {
               rv = NULL;
             }
             if (rv) {
               // forbid compound word, if it is a non compound word with typical
               // fault
               if (checkcompoundrep || forbiddenword) {
-
-                if (checkcompoundrep && cpdrep_check(word.c_str(), len))
+                struct hentry* rv2 = NULL;
+
+                if (checkcompoundrep && cpdrep_check(word, len))
                   return NULL;
 
                 // check first part
-                if (strncmp(rv->word, word.c_str() + i, rv->blen) == 0) {
+                if (strncmp(rv->word, word + i, rv->blen) == 0) {
                   char r = st[i + rv->blen];
                   st[i + rv->blen] = '\0';
 
                   if (checkcompoundrep && cpdrep_check(st.c_str(), i + rv->blen)) {
                     st[ + i + rv->blen] = r;
                     continue;
                   }
 
                   if (forbiddenword) {
-                    struct hentry* rv2 = lookup(word.c_str());
+                    rv2 = lookup(word);
                     if (!rv2)
-                      rv2 = affix_check(word.c_str(), len);
+                      rv2 = affix_check(word, len);
                     if (rv2 && rv2->astr &&
                         TESTAFF(rv2->astr, forbiddenword, rv2->alen) &&
                         (strncmp(rv2->word, st.c_str(), i + rv->blen) == 0)) {
                       return NULL;
                     }
                   }
                   st[i + rv->blen] = r;
                 }
@@ -2110,64 +2243,65 @@ struct hentry* AffixMgr::compound_check(
           soldi = 0;
           len = oldlen;
           cmin = oldcmin;
           cmax = oldcmax;
         }
         scpd++;
 
       } while (!onlycpdrule && simplifiedcpd &&
-               scpd <= checkcpdtable.size());  // end of simplifiedcpd loop
+               scpd <= numcheckcpd);  // end of simplifiedcpd loop
 
       scpd = 0;
       wordnum = oldwordnum;
       numsyllable = oldnumsyllable;
 
       if (soldi != 0) {
         i = soldi;
         st.assign(word);  // XXX add more optim.
         soldi = 0;
       } else
         st[i] = ch;
 
-    } while (!defcpdtable.empty() && oldwordnum == 0 &&
+    } while (numdefcpd && oldwordnum == 0 &&
              onlycpdrule++ < 1);  // end of onlycpd loop
   }
 
   return NULL;
 }
 
 // check if compound word is correctly spelled
 // hu_mov_rule = spec. Hungarian rule (XXX)
 int AffixMgr::compound_check_morph(const char* word,
                                    int len,
                                    short wordnum,
                                    short numsyllable,
                                    short maxwordnum,
                                    short wnum,
                                    hentry** words,
                                    hentry** rwords,
-                                   char hu_mov_rule,
-                                   std::string& result,
-                                   const std::string* partresult) {
+                                   char hu_mov_rule = 0,
+                                   char** result = NULL,
+                                   char* partresult = NULL) {
   int i;
   short oldnumsyllable, oldnumsyllable2, oldwordnum, oldwordnum2;
   int ok = 0;
 
   struct hentry* rv = NULL;
   struct hentry* rv_first;
   std::string st;
   char ch;
 
   int checked_prefix;
-  std::string presult;
+  char presult[MAXLNLEN];
 
   int cmin;
   int cmax;
 
+  int onlycpdrule;
   char affixed = 0;
   hentry** oldwords = words;
 
   setcminmax(&cmin, &cmax, word, len);
 
   st.assign(word);
 
   for (i = cmin; i < cmax; i++) {
@@ -2175,133 +2309,138 @@ int AffixMgr::compound_check_morph(const
     if (utf8) {
       for (; (st[i] & 0xc0) == 0x80; i++)
         ;
       if (i >= cmax)
         return 0;
     }
 
     words = oldwords;
-    int onlycpdrule = (words) ? 1 : 0;
+    onlycpdrule = (words) ? 1 : 0;
 
     do {  // onlycpdrule loop
 
       oldnumsyllable = numsyllable;
       oldwordnum = wordnum;
       checked_prefix = 0;
 
       ch = st[i];
       st[i] = '\0';
       sfx = NULL;
 
       // FIRST WORD
 
       affixed = 1;
 
-      presult.clear();
+      *presult = '\0';
       if (partresult)
-        presult.append(*partresult);
+        mystrcat(presult, partresult, MAXLNLEN);
 
       rv = lookup(st.c_str());  // perhaps without prefix
 
       // search homonym with compound flag
       while ((rv) && !hu_mov_rule &&
              ((needaffix && TESTAFF(rv->astr, needaffix, rv->alen)) ||
               !((compoundflag && !words && !onlycpdrule &&
                  TESTAFF(rv->astr, compoundflag, rv->alen)) ||
                 (compoundbegin && !wordnum && !onlycpdrule &&
                  TESTAFF(rv->astr, compoundbegin, rv->alen)) ||
                 (compoundmiddle && wordnum && !words && !onlycpdrule &&
                  TESTAFF(rv->astr, compoundmiddle, rv->alen)) ||
-                (!defcpdtable.empty() && onlycpdrule &&
+                (numdefcpd && onlycpdrule &&
                  ((!words && !wordnum &&
                    defcpd_check(&words, wnum, rv, rwords, 0)) ||
                   (words &&
                    defcpd_check(&words, wnum, rv, rwords, 0))))))) {
         rv = rv->next_homonym;
       }
 
       if (rv)
         affixed = 0;
 
       if (rv) {
-        presult.push_back(MSEP_FLD);
-        presult.append(MORPH_PART);
-        presult.append(st.c_str());
+        sprintf(presult + strlen(presult), "%c%s%s", MSEP_FLD, MORPH_PART, st.c_str());
         if (!HENTRY_FIND(rv, MORPH_STEM)) {
-          presult.push_back(MSEP_FLD);
-          presult.append(MORPH_STEM);
-          presult.append(st.c_str());
+          sprintf(presult + strlen(presult), "%c%s%s", MSEP_FLD, MORPH_STEM,
+                  st.c_str());
         }
+        // store the pointer of the hash entry
+        //            sprintf(presult + strlen(presult), "%c%s%p", MSEP_FLD,
+        //            MORPH_HENTRY, rv);
         if (HENTRY_DATA(rv)) {
-          presult.push_back(MSEP_FLD);
-          presult.append(HENTRY_DATA2(rv));
+          sprintf(presult + strlen(presult), "%c%s", MSEP_FLD,
+                  HENTRY_DATA2(rv));
         }
       }
 
       if (!rv) {
+        if (onlycpdrule && strlen(*result) > MAXLNLEN / 10)
+          break;
         if (compoundflag &&
             !(rv =
                   prefix_check(st.c_str(), i, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN,
                                compoundflag))) {
-          if (((rv = suffix_check(st.c_str(), i, 0, NULL, FLAG_NULL,
+          if (((rv = suffix_check(st.c_str(), i, 0, NULL, NULL, 0, NULL, FLAG_NULL,
                                   compoundflag,
                                   hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) ||
                (compoundmoresuffixes &&
                 (rv = suffix_check_twosfx(st.c_str(), i, 0, NULL, compoundflag)))) &&
               !hu_mov_rule && sfx->getCont() &&
               ((compoundforbidflag &&
                 TESTAFF(sfx->getCont(), compoundforbidflag,
                         sfx->getContLen())) ||
                (compoundend &&
                 TESTAFF(sfx->getCont(), compoundend, sfx->getContLen())))) {
             rv = NULL;
           }
         }
 
         if (rv ||
             (((wordnum == 0) && compoundbegin &&
-              ((rv = suffix_check(st.c_str(), i, 0, NULL, FLAG_NULL,
+              ((rv = suffix_check(st.c_str(), i, 0, NULL, NULL, 0, NULL, FLAG_NULL,
                                   compoundbegin,
                                   hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) ||
                (compoundmoresuffixes &&
                 (rv = suffix_check_twosfx(
                      st.c_str(), i, 0, NULL,
                      compoundbegin))) ||  // twofold suffix+compound
                (rv = prefix_check(st.c_str(), i,
                                   hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN,
                                   compoundbegin)))) ||
              ((wordnum > 0) && compoundmiddle &&
-              ((rv = suffix_check(st.c_str(), i, 0, NULL, FLAG_NULL,
+              ((rv = suffix_check(st.c_str(), i, 0, NULL, NULL, 0, NULL, FLAG_NULL,
                                   compoundmiddle,
                                   hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) ||
                (compoundmoresuffixes &&
                 (rv = suffix_check_twosfx(
                      st.c_str(), i, 0, NULL,
                      compoundmiddle))) ||  // twofold suffix+compound
                (rv = prefix_check(st.c_str(), i,
                                   hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN,
                                   compoundmiddle)))))) {
-          std::string p;
+          // char * p = prefix_check_morph(st, i, 0, compound);
+          char* p = NULL;
           if (compoundflag)
             p = affix_check_morph(st.c_str(), i, compoundflag);
-          if (p.empty()) {
+          if (!p || (*p == '\0')) {
+            if (p)
+              free(p);
+            p = NULL;
             if ((wordnum == 0) && compoundbegin) {
               p = affix_check_morph(st.c_str(), i, compoundbegin);
             } else if ((wordnum > 0) && compoundmiddle) {
               p = affix_check_morph(st.c_str(), i, compoundmiddle);
             }
           }
-          if (!p.empty()) {
-            presult.push_back(MSEP_FLD);
-            presult.append(MORPH_PART);
-            presult.append(st.c_str());
-            line_uniq_app(p, MSEP_REC);
-            presult.append(p);
+          if (p && (*p != '\0')) {
+            sprintf(presult + strlen(presult), "%c%s%s%s", MSEP_FLD, MORPH_PART,
+                    st.c_str(), line_uniq_app(&p, MSEP_REC));
           }
+          if (p)
+            free(p);
           checked_prefix = 1;
         }
         // else check forbiddenwords
       } else if (rv->astr && (TESTAFF(rv->astr, forbiddenword, rv->alen) ||
                               TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) ||
                               TESTAFF(rv->astr, needaffix, rv->alen))) {
         st[i] = ch;
         continue;
@@ -2363,17 +2502,17 @@ int AffixMgr::compound_check_morph(const
             ) &&
            !((checkcompoundtriple && !words &&  // test triple letters
               (word[i - 1] == word[i]) &&
               (((i > 1) && (word[i - 1] == word[i - 2])) ||
                ((word[i - 1] == word[i + 1]))  // may be word[i+1] == '\0'
                )) ||
              (
                  // test CHECKCOMPOUNDPATTERN
-                 !checkcpdtable.empty() && !words &&
+                 numcheckcpd && !words &&
                  cpdpat_check(word, i, rv, NULL, affixed)) ||
              (checkcompoundcase && !words && cpdcase_check(word, i))))
           // LANG_hu section: spec. Hungarian rule
           ||
           ((!rv) && (langnum == LANG_hu) && hu_mov_rule &&
            (rv = affix_check(st.c_str(), i)) &&
            (sfx && sfx->getCont() &&
             (TESTAFF(sfx->getCont(), (unsigned short)'x', sfx->getContLen()) ||
@@ -2397,39 +2536,41 @@ int AffixMgr::compound_check_morph(const
         rv = lookup((word + i));  // perhaps without prefix
 
         // search homonym with compound flag
         while ((rv) && ((needaffix && TESTAFF(rv->astr, needaffix, rv->alen)) ||
                         !((compoundflag && !words &&
                            TESTAFF(rv->astr, compoundflag, rv->alen)) ||
                           (compoundend && !words &&
                            TESTAFF(rv->astr, compoundend, rv->alen)) ||
-                          (!defcpdtable.empty() && words &&
+                          (numdefcpd && words &&
                            defcpd_check(&words, wnum + 1, rv, NULL, 1))))) {
           rv = rv->next_homonym;
         }
 
         if (rv && words && words[wnum + 1]) {
-          result.append(presult);
-          result.append(" ");
-          result.append(MORPH_PART);
-          result.append(word + i);
+          mystrcat(*result, presult, MAXLNLEN);
+          mystrcat(*result, " ", MAXLNLEN);
+          mystrcat(*result, MORPH_PART, MAXLNLEN);
+          mystrcat(*result, word + i, MAXLNLEN);
           if (complexprefixes && HENTRY_DATA(rv))
-            result.append(HENTRY_DATA2(rv));
+            mystrcat(*result, HENTRY_DATA2(rv), MAXLNLEN);
           if (!HENTRY_FIND(rv, MORPH_STEM)) {
-            result.append(" ");
-            result.append(MORPH_STEM);
-            result.append(HENTRY_WORD(rv));
+            mystrcat(*result, " ", MAXLNLEN);
+            mystrcat(*result, MORPH_STEM, MAXLNLEN);
+            mystrcat(*result, HENTRY_WORD(rv), MAXLNLEN);
           }
           // store the pointer of the hash entry
+          //                  sprintf(*result + strlen(*result), " %s%p",
+          //                  MORPH_HENTRY, rv);
           if (!complexprefixes && HENTRY_DATA(rv)) {
-            result.append(" ");
-            result.append(HENTRY_DATA2(rv));
+            mystrcat(*result, " ", MAXLNLEN);
+            mystrcat(*result, HENTRY_DATA2(rv), MAXLNLEN);
           }
-          result.append("\n");
+          mystrcat(*result, "\n", MAXLNLEN);
           return 0;
         }
 
         oldnumsyllable2 = numsyllable;
         oldwordnum2 = wordnum;
 
         // LANG_hu section: spec. Hungarian rule
         if ((rv) && (langnum == LANG_hu) &&
@@ -2460,36 +2601,38 @@ int AffixMgr::compound_check_morph(const
             ((compoundflag && TESTAFF(rv->astr, compoundflag, rv->alen)) ||
              (compoundend && TESTAFF(rv->astr, compoundend, rv->alen))) &&
             (((cpdwordmax == -1) || (wordnum + 1 < cpdwordmax)) ||
              ((cpdmaxsyllable != 0) &&
               (numsyllable + get_syllable(std::string(HENTRY_WORD(rv), rv->blen)) <=
                cpdmaxsyllable))) &&
             ((!checkcompounddup || (rv != rv_first)))) {
           // bad compound word
-          result.append(presult);
-          result.append(" ");
-          result.append(MORPH_PART);
-          result.append(word + i);
+          mystrcat(*result, presult, MAXLNLEN);
+          mystrcat(*result, " ", MAXLNLEN);
+          mystrcat(*result, MORPH_PART, MAXLNLEN);
+          mystrcat(*result, word + i, MAXLNLEN);
 
           if (HENTRY_DATA(rv)) {
             if (complexprefixes)
-              result.append(HENTRY_DATA2(rv));
+              mystrcat(*result, HENTRY_DATA2(rv), MAXLNLEN);
             if (!HENTRY_FIND(rv, MORPH_STEM)) {
-              result.append(" ");
-              result.append(MORPH_STEM);
-              result.append(HENTRY_WORD(rv));
+              mystrcat(*result, " ", MAXLNLEN);
+              mystrcat(*result, MORPH_STEM, MAXLNLEN);
+              mystrcat(*result, HENTRY_WORD(rv), MAXLNLEN);
             }
             // store the pointer of the hash entry
+            //                        sprintf(*result + strlen(*result), "
+            //                        %s%p", MORPH_HENTRY, rv);
             if (!complexprefixes) {
-              result.append(" ");
-              result.append(HENTRY_DATA2(rv));
+              mystrcat(*result, " ", MAXLNLEN);
+              mystrcat(*result, HENTRY_DATA2(rv), MAXLNLEN);
             }
           }
-          result.append("\n");
+          mystrcat(*result, "\n", MAXLNLEN);
           ok = 1;
         }
 
         numsyllable = oldnumsyllable2;
         wordnum = oldwordnum2;
 
         // perhaps second word has prefix or/and suffix
         sfx = NULL;
@@ -2501,34 +2644,37 @@ int AffixMgr::compound_check_morph(const
           rv = NULL;
 
         if (!rv && compoundend && !onlycpdrule) {
           sfx = NULL;
           pfx = NULL;
           rv = affix_check((word + i), strlen(word + i), compoundend);
         }
 
-        if (!rv && !defcpdtable.empty() && words) {
+        if (!rv && numdefcpd && words) {
           rv = affix_check((word + i), strlen(word + i), 0, IN_CPD_END);
           if (rv && words && defcpd_check(&words, wnum + 1, rv, NULL, 1)) {
-            std::string m;
+            char* m = NULL;
             if (compoundflag)
               m = affix_check_morph((word + i), strlen(word + i), compoundflag);
-            if (m.empty() && compoundend) {
+            if ((!m || *m == '\0') && compoundend) {
+              if (m)
+                free(m);
               m = affix_check_morph((word + i), strlen(word + i), compoundend);
             }
-            result.append(presult);
-            if (!m.empty()) {
-              result.push_back(MSEP_FLD);
-              result.append(MORPH_PART);
-              result.append(word + i);
-              line_uniq_app(m, MSEP_REC);
-              result.append(m);
+            mystrcat(*result, presult, MAXLNLEN);
+            if (m || (*m != '\0')) {
+              char m2[MAXLNLEN];
+              sprintf(m2, "%c%s%s%s", MSEP_FLD, MORPH_PART, word + i,
+                      line_uniq_app(&m, MSEP_REC));
+              mystrcat(*result, m2, MAXLNLEN);
             }
-            result.append("\n");
+            if (m)
+              free(m);
+            mystrcat(*result, "\n", MAXLNLEN);
             ok = 1;
           }
         }
 
         // check non_compound flag in suffix and prefix
         if ((rv) &&
             ((pfx && pfx->getCont() &&
               TESTAFF(pfx->getCont(), compoundforbidflag, pfx->getContLen())) ||
@@ -2562,17 +2708,17 @@ int AffixMgr::compound_check_morph(const
           // + 1 word, if syllable number of the prefix > 1 (hungarian
           // convention)
           if (pfx && (get_syllable(pfx->getKey()) > 1))
             wordnum++;
 
           // increment syllable num, if last word has a SYLLABLENUM flag
           // and the suffix is beginning `s'
 
-          if (!cpdsyllablenum.empty()) {
+          if (cpdsyllablenum) {
             switch (sfxflag) {
               case 'c': {
                 numsyllable += 2;
                 break;
               }
               case 'J': {
                 numsyllable += 1;
                 break;
@@ -2594,73 +2740,94 @@ int AffixMgr::compound_check_morph(const
         // second word is acceptable, as a word with prefix or/and suffix?
         // hungarian conventions: compounding is acceptable,
         // when compound forms consist 2 word, otherwise
         // the syllable number of root words is 6, or lesser.
         if ((rv) &&
             (((cpdwordmax == -1) || (wordnum + 1 < cpdwordmax)) ||
              ((cpdmaxsyllable != 0) && (numsyllable <= cpdmaxsyllable))) &&
             ((!checkcompounddup || (rv != rv_first)))) {
-          std::string m;
+          char* m = NULL;
           if (compoundflag)
             m = affix_check_morph((word + i), strlen(word + i), compoundflag);
-          if (m.empty() && compoundend) {
+          if ((!m || *m == '\0') && compoundend) {
+            if (m)
+              free(m);
             m = affix_check_morph((word + i), strlen(word + i), compoundend);
           }
-          result.append(presult);
-          if (!m.empty()) {
-            result.push_back(MSEP_FLD);
-            result.append(MORPH_PART);
-            result.append(word + 1);
-            line_uniq_app(m, MSEP_REC);
-            result.append(m);
+          mystrcat(*result, presult, MAXLNLEN);
+          if (m && (*m != '\0')) {
+            char m2[MAXLNLEN];
+            sprintf(m2, "%c%s%s%s", MSEP_FLD, MORPH_PART, word + i,
+                    line_uniq_app(&m, MSEP_REC));
+            mystrcat(*result, m2, MAXLNLEN);
           }
-          result.push_back(MSEP_REC);
+          if (m)
+            free(m);
+          if (strlen(*result) + 1 < MAXLNLEN)
+            sprintf(*result + strlen(*result), "%c", MSEP_REC);
           ok = 1;
         }
 
         numsyllable = oldnumsyllable2;
         wordnum = oldwordnum2;
 
         // perhaps second word is a compound word (recursive call)
         if ((wordnum < maxwordnum) && (ok == 0)) {
           compound_check_morph((word + i), strlen(word + i), wordnum + 1,
                                numsyllable, maxwordnum, wnum + 1, words, rwords, 0,
-                               result, &presult);
+                               result, presult);
         } else {
           rv = NULL;
         }
       }
       st[i] = ch;
       wordnum = oldwordnum;
       numsyllable = oldnumsyllable;
 
-    } while (!defcpdtable.empty() && oldwordnum == 0 &&
+    } while (numdefcpd && oldwordnum == 0 &&
              onlycpdrule++ < 1);  // end of onlycpd loop
   }
   return 0;
 }
 
 
+// return 1 if s1 (reversed) is a leading subset of end of s2
+/* inline int AffixMgr::isRevSubset(const char * s1, const char * end_of_s2, int
+ len)
+ {
+    while ((len > 0) && *s1 && (*s1 == *end_of_s2)) {
+        s1++;
+        end_of_s2--;
+        len--;
+    }
+    return (*s1 == '\0');
+ }
+ */
+
 inline int AffixMgr::isRevSubset(const char* s1,
                                  const char* end_of_s2,
                                  int len) {
   while ((len > 0) && (*s1 != '\0') && ((*s1 == *end_of_s2) || (*s1 == '.'))) {
     s1++;
     end_of_s2--;
     len--;
   }
   return (*s1 == '\0');
 }
 
 // check word for suffixes
+
 struct hentry* AffixMgr::suffix_check(const char* word,
                                       int len,
                                       int sfxopts,
                                       PfxEntry* ppfx,
+                                      char** wlst,
+                                      int maxSug,
+                                      int* ns,
                                       const FLAG cclass,
                                       const FLAG needflag,
                                       char in_compound) {
   struct hentry* rv = NULL;
   PfxEntry* ep = ppfx;
 
   // first handle the special case of 0 length suffixes
   SfxEntry* se = sStart[0];
@@ -2689,17 +2856,17 @@ struct hentry* AffixMgr::suffix_check(co
              (TESTAFF(se->getCont(), onlyincompound, se->getContLen())))) &&
           // needaffix on prefix or first suffix
           (cclass ||
            !(se->getCont() &&
              TESTAFF(se->getCont(), needaffix, se->getContLen())) ||
            (ppfx &&
             !((ep->getCont()) &&
               TESTAFF(ep->getCont(), needaffix, ep->getContLen()))))) {
-        rv = se->checkword(word, len, sfxopts, ppfx,
+        rv = se->checkword(word, len, sfxopts, ppfx, wlst, maxSug, ns,
                            (FLAG)cclass, needflag,
                            (in_compound ? 0 : onlyincompound));
         if (rv) {
           sfx = se;  // BUG: sfx not stateless
           return rv;
         }
       }
     }
@@ -2740,17 +2907,17 @@ struct hentry* AffixMgr::suffix_check(co
            !(sptr->getCont() &&
              TESTAFF(sptr->getCont(), needaffix, sptr->getContLen())) ||
            (ppfx &&
             !((ep->getCont()) &&
               TESTAFF(ep->getCont(), needaffix, ep->getContLen())))))
         if (in_compound != IN_CPD_END || ppfx ||
             !(sptr->getCont() &&
               TESTAFF(sptr->getCont(), onlyincompound, sptr->getContLen()))) {
-          rv = sptr->checkword(word, len, sfxopts, ppfx,
+          rv = sptr->checkword(word, len, sfxopts, ppfx, wlst, maxSug, ns,
                                cclass, needflag,
                                (in_compound ? 0 : onlyincompound));
           if (rv) {
             sfx = sptr;                 // BUG: sfx not stateless
             sfxflag = sptr->getFlag();  // BUG: sfxflag not stateless
             if (!sptr->getCont())
               sfxappnd = sptr->getKey();  // BUG: sfxappnd not stateless
             // LANG_hu section: spec. Hungarian rule
@@ -2813,65 +2980,69 @@ struct hentry* AffixMgr::suffix_check_tw
     } else {
       sptr = sptr->getNextNE();
     }
   }
 
   return NULL;
 }
 
-std::string AffixMgr::suffix_check_twosfx_morph(const char* word,
-                                                int len,
-                                                int sfxopts,
-                                                PfxEntry* ppfx,
-                                                const FLAG needflag) {
+char* AffixMgr::suffix_check_twosfx_morph(const char* word,
+                                          int len,
+                                          int sfxopts,
+                                          PfxEntry* ppfx,
+                                          const FLAG needflag) {
   std::string result;
   std::string result2;
   std::string result3;
 
+  char* st;
+
   // first handle the special case of 0 length suffixes
   SfxEntry* se = sStart[0];
   while (se) {
     if (contclasses[se->getFlag()]) {
-      std::string st = se->check_twosfx_morph(word, len, sfxopts, ppfx, needflag);
-      if (!st.empty()) {
+      st = se->check_twosfx_morph(word, len, sfxopts, ppfx, needflag);
+      if (st) {
         if (ppfx) {
           if (ppfx->getMorph()) {
             result.append(ppfx->getMorph());
             result.append(" ");
           } else
             debugflag(result, ppfx->getFlag());
         }
         result.append(st);
+        free(st);
         if (se->getMorph()) {
           result.append(" ");
           result.append(se->getMorph());
         } else
           debugflag(result, se->getFlag());
         result.append("\n");
       }
     }
     se = se->getNext();
   }
 
   // now handle the general case
   if (len == 0)
-    return std::string();  // FULLSTRIP
+    return NULL;  // FULLSTRIP
   unsigned char sp = *((const unsigned char*)(word + len - 1));
   SfxEntry* sptr = sStart[sp];
 
   while (sptr) {
     if (isRevSubset(sptr->getKey(), word + len - 1, len)) {
       if (contclasses[sptr->getFlag()]) {
-        std::string st = sptr->check_twosfx_morph(word, len, sfxopts, ppfx, needflag);
-        if (!st.empty()) {
+        st = sptr->check_twosfx_morph(word, len, sfxopts, ppfx, needflag);
+        if (st) {
           sfxflag = sptr->getFlag();  // BUG: sfxflag not stateless
           if (!sptr->getCont())
             sfxappnd = sptr->getKey();  // BUG: sfxappnd not stateless
           result2.assign(st);
+          free(st);
 
           result3.clear();
 
           if (sptr->getMorph()) {
             result3.append(" ");
             result3.append(sptr->getMorph());
           } else
             debugflag(result3, sptr->getFlag());
@@ -2881,30 +3052,35 @@ std::string AffixMgr::suffix_check_twosf
         }
       }
       sptr = sptr->getNextEQ();
     } else {
       sptr = sptr->getNextNE();
     }
   }
 
-  return result;
+  if (!result.empty())
+    return mystrdup(result.c_str());
+
+  return NULL;
 }
 
-std::string AffixMgr::suffix_check_morph(const char* word,
-                                         int len,
-                                         int sfxopts,
-                                         PfxEntry* ppfx,
-                                         const FLAG cclass,
-                                         const FLAG needflag,
-                                         char in_compound) {
-  std::string result;
+char* AffixMgr::suffix_check_morph(const char* word,
+                                   int len,
+                                   int sfxopts,
+                                   PfxEntry* ppfx,
+                                   const FLAG cclass,
+                                   const FLAG needflag,
+                                   char in_compound) {
+  char result[MAXLNLEN];
 
   struct hentry* rv = NULL;
 
+  result[0] = '\0';
+
   PfxEntry* ep = ppfx;
 
   // first handle the special case of 0 length suffixes
   SfxEntry* se = sStart[0];
   while (se) {
     if (!cclass || se->getCont()) {
       // suffixes are not allowed in beginning of compounds
       if (((((in_compound != IN_CPD_BEGIN)) ||  // && !cclass
@@ -2928,53 +3104,56 @@ std::string AffixMgr::suffix_check_morph
                (TESTAFF(se->getCont(), onlyincompound, se->getContLen()))))) &&
            // needaffix on prefix or first suffix
            (cclass ||
             !(se->getCont() &&
               TESTAFF(se->getCont(), needaffix, se->getContLen())) ||
             (ppfx &&
              !((ep->getCont()) &&
                TESTAFF(ep->getCont(), needaffix, ep->getContLen()))))))
-        rv = se->checkword(word, len, sfxopts, ppfx, cclass,
-                           needflag, FLAG_NULL);
+        rv = se->checkword(word, len, sfxopts, ppfx, NULL, 0, 0, cclass,
+                           needflag);
       while (rv) {
         if (ppfx) {
           if (ppfx->getMorph()) {
-            result.append(ppfx->getMorph());
-            result.append(" ");
+            mystrcat(result, ppfx->getMorph(), MAXLNLEN);
+            mystrcat(result, " ", MAXLNLEN);
           } else
             debugflag(result, ppfx->getFlag());
         }
         if (complexprefixes && HENTRY_DATA(rv))
-          result.append(HENTRY_DATA2(rv));
+          mystrcat(result, HENTRY_DATA2(rv), MAXLNLEN);
         if (!HENTRY_FIND(rv, MORPH_STEM)) {
-          result.append(" ");
-          result.append(MORPH_STEM);
-          result.append(HENTRY_WORD(rv));
+          mystrcat(result, " ", MAXLNLEN);
+          mystrcat(result, MORPH_STEM, MAXLNLEN);
+          mystrcat(result, HENTRY_WORD(rv), MAXLNLEN);
         }
+        // store the pointer of the hash entry
+        //            sprintf(result + strlen(result), " %s%p", MORPH_HENTRY,
+        //            rv);
 
         if (!complexprefixes && HENTRY_DATA(rv)) {
-          result.append(" ");
-          result.append(HENTRY_DATA2(rv));
+          mystrcat(result, " ", MAXLNLEN);
+          mystrcat(result, HENTRY_DATA2(rv), MAXLNLEN);
         }
         if (se->getMorph()) {
-          result.append(" ");
-          result.append(se->getMorph());
+          mystrcat(result, " ", MAXLNLEN);
+          mystrcat(result, se->getMorph(), MAXLNLEN);
         } else
           debugflag(result, se->getFlag());
-        result.append("\n");
+        mystrcat(result, "\n", MAXLNLEN);
         rv = se->get_next_homonym(rv, sfxopts, ppfx, cclass, needflag);
       }
     }
     se = se->getNext();
   }
 
   // now handle the general case
   if (len == 0)
-    return std::string();  // FULLSTRIP
+    return NULL;  // FULLSTRIP
   unsigned char sp = *((const unsigned char*)(word + len - 1));
   SfxEntry* sptr = sStart[sp];
 
   while (sptr) {
     if (isRevSubset(sptr->getKey(), word + len - 1, len)) {
       // suffixes are not allowed in beginning of compounds
       if (((((in_compound != IN_CPD_BEGIN)) ||  // && !cclass
             // except when signed with compoundpermitflag flag
@@ -2995,70 +3174,76 @@ std::string AffixMgr::suffix_check_morph
            // fogemorpheme
            (in_compound ||
             !((sptr->getCont() && (TESTAFF(sptr->getCont(), onlyincompound,
                                            sptr->getContLen()))))) &&
            // needaffix on first suffix
            (cclass ||
             !(sptr->getCont() &&
               TESTAFF(sptr->getCont(), needaffix, sptr->getContLen())))))
-        rv = sptr->checkword(word, len, sfxopts, ppfx, cclass,
-                             needflag, FLAG_NULL);
+        rv = sptr->checkword(word, len, sfxopts, ppfx, NULL, 0, 0, cclass,
+                             needflag);
       while (rv) {
         if (ppfx) {
           if (ppfx->getMorph()) {
-            result.append(ppfx->getMorph());
-            result.append(" ");
+            mystrcat(result, ppfx->getMorph(), MAXLNLEN);
+            mystrcat(result, " ", MAXLNLEN);
           } else
             debugflag(result, ppfx->getFlag());
         }
         if (complexprefixes && HENTRY_DATA(rv))
-          result.append(HENTRY_DATA2(rv));
+          mystrcat(result, HENTRY_DATA2(rv), MAXLNLEN);
         if (!HENTRY_FIND(rv, MORPH_STEM)) {
-          result.append(" ");
-          result.append(MORPH_STEM);
-          result.append(HENTRY_WORD(rv));
+          mystrcat(result, " ", MAXLNLEN);
+          mystrcat(result, MORPH_STEM, MAXLNLEN);
+          mystrcat(result, HENTRY_WORD(rv), MAXLNLEN);
         }
+        // store the pointer of the hash entry
+        //                    sprintf(result + strlen(result), " %s%p",
+        //                    MORPH_HENTRY, rv);
 
         if (!complexprefixes && HENTRY_DATA(rv)) {
-          result.append(" ");
-          result.append(HENTRY_DATA2(rv));
+          mystrcat(result, " ", MAXLNLEN);
+          mystrcat(result, HENTRY_DATA2(rv), MAXLNLEN);
         }
 
         if (sptr->getMorph()) {
-          result.append(" ");
-          result.append(sptr->getMorph());
+          mystrcat(result, " ", MAXLNLEN);
+          mystrcat(result, sptr->getMorph(), MAXLNLEN);
         } else
           debugflag(result, sptr->getFlag());
-        result.append("\n");
+        mystrcat(result, "\n", MAXLNLEN);
         rv = sptr->get_next_homonym(rv, sfxopts, ppfx, cclass, needflag);
       }
       sptr = sptr->getNextEQ();
     } else {
       sptr = sptr->getNextNE();
     }
   }
 
-  return result;
+  if (*result)
+    return mystrdup(result);
+  return NULL;
 }
 
 // check if word with affixes is correctly spelled
 struct hentry* AffixMgr::affix_check(const char* word,
                                      int len,
                                      const FLAG needflag,
                                      char in_compound) {
   struct hentry* rv = NULL;
 
   // check all prefixes (also crossed with suffixes if allowed)
   rv = prefix_check(word, len, in_compound, needflag);
   if (rv)
     return rv;
 
   // if still not found check all suffixes
-  rv = suffix_check(word, len, 0, NULL, FLAG_NULL, needflag, in_compound);
+  rv = suffix_check(word, len, 0, NULL, NULL, 0, NULL, FLAG_NULL, needflag,
+                    in_compound);
 
   if (havecontclass) {
     sfx = NULL;
     pfx = NULL;
 
     if (rv)
       return rv;
     // if still not found check all two-level suffixes
@@ -3069,153 +3254,77 @@ struct hentry* AffixMgr::affix_check(con
     // if still not found check all two-level suffixes
     rv = prefix_check_twosfx(word, len, IN_CPD_NOT, needflag);
   }
 
   return rv;
 }
 
 // check if word with affixes is correctly spelled
-std::string AffixMgr::affix_check_morph(const char* word,
+char* AffixMgr::affix_check_morph(const char* word,
                                   int len,
                                   const FLAG needflag,
                                   char in_compound) {
-  std::string result;
+  char result[MAXLNLEN];
+  char* st = NULL;
+
+  *result = '\0';
 
   // check all prefixes (also crossed with suffixes if allowed)
-  std::string st = prefix_check_morph(word, len, in_compound);
-  if (!st.empty()) {
-    result.append(st);
+  st = prefix_check_morph(word, len, in_compound);
+  if (st) {
+    mystrcat(result, st, MAXLNLEN);
+    free(st);
   }
 
   // if still not found check all suffixes
   st = suffix_check_morph(word, len, 0, NULL, '\0', needflag, in_compound);
-  if (!st.empty()) {
-    result.append(st);
+  if (st) {
+    mystrcat(result, st, MAXLNLEN);
+    free(st);
   }
 
   if (havecontclass) {
     sfx = NULL;
     pfx = NULL;
     // if still not found check all two-level suffixes
     st = suffix_check_twosfx_morph(word, len, 0, NULL, needflag);
-    if (!st.empty()) {
-      result.append(st);
+    if (st) {
+      mystrcat(result, st, MAXLNLEN);
+      free(st);
     }
 
     // if still not found check all two-level suffixes
     st = prefix_check_twosfx_morph(word, len, IN_CPD_NOT, needflag);
-    if (!st.empty()) {
-      result.append(st);
+    if (st) {
+      mystrcat(result, st, MAXLNLEN);
+      free(st);
     }
   }
 
-  return result;
+  return mystrdup(result);
 }
 
-// morphcmp(): compare MORPH_DERI_SFX, MORPH_INFL_SFX and MORPH_TERM_SFX fields
-// in the first line of the inputs
-// return 0, if inputs equal
-// return 1, if inputs may equal with a secondary suffix
-// otherwise return -1
-static int morphcmp(const char* s, const char* t) {
-  int se = 0;
-  int te = 0;
-  const char* sl;
-  const char* tl;
-  const char* olds;
-  const char* oldt;
-  if (!s || !t)
-    return 1;
-  olds = s;
-  sl = strchr(s, '\n');
-  s = strstr(s, MORPH_DERI_SFX);
-  if (!s || (sl && sl < s))
-    s = strstr(olds, MORPH_INFL_SFX);
-  if (!s || (sl && sl < s)) {
-    s = strstr(olds, MORPH_TERM_SFX);
-    olds = NULL;
-  }
-  oldt = t;
-  tl = strchr(t, '\n');
-  t = strstr(t, MORPH_DERI_SFX);
-  if (!t || (tl && tl < t))
-    t = strstr(oldt, MORPH_INFL_SFX);
-  if (!t || (tl && tl < t)) {
-    t = strstr(oldt, MORPH_TERM_SFX);
-    oldt = NULL;
-  }
-  while (s && t && (!sl || sl > s) && (!tl || tl > t)) {
-    s += MORPH_TAG_LEN;
-    t += MORPH_TAG_LEN;
-    se = 0;
-    te = 0;
-    while ((*s == *t) && !se && !te) {
-      s++;
-      t++;
-      switch (*s) {
-        case ' ':
-        case '\n':
-        case '\t':
-        case '\0':
-          se = 1;
-      }
-      switch (*t) {
-        case ' ':
-        case '\n':
-        case '\t':
-        case '\0':
-          te = 1;
-      }
-    }
-    if (!se || !te) {
-      // not terminal suffix difference
-      if (olds)
-        return -1;
-      return 1;
-    }
-    olds = s;
-    s = strstr(s, MORPH_DERI_SFX);
-    if (!s || (sl && sl < s))
-      s = strstr(olds, MORPH_INFL_SFX);
-    if (!s || (sl && sl < s)) {
-      s = strstr(olds, MORPH_TERM_SFX);
-      olds = NULL;
-    }
-    oldt = t;
-    t = strstr(t, MORPH_DERI_SFX);
-    if (!t || (tl && tl < t))
-      t = strstr(oldt, MORPH_INFL_SFX);
-    if (!t || (tl && tl < t)) {
-      t = strstr(oldt, MORPH_TERM_SFX);
-      oldt = NULL;
-    }
-  }
-  if (!s && !t && se && te)
-    return 0;
-  return 1;
-}
-
-std::string AffixMgr::morphgen(const char* ts,
-                               int wl,
-                               const unsigned short* ap,
-                               unsigned short al,
-                               const char* morph,
-                               const char* targetmorph,
+char* AffixMgr::morphgen(const char* ts,
+                         int wl,
+                         const unsigned short* ap,
+                         unsigned short al,
+                         const char* morph,
+                         const char* targetmorph,
                          int level) {
   // handle suffixes
   if (!morph)
-    return std::string();
+    return NULL;
 
   // check substandard flag
   if (TESTAFF(ap, substandard, al))
-    return std::string();
+    return NULL;
 
   if (morphcmp(morph, targetmorph) == 0)
-    return ts;
+    return mystrdup(ts);
 
   size_t stemmorphcatpos;
   std::string mymorph;
 
   // use input suffix fields, if exist
   if (strstr(morph, MORPH_INFL_SFX) || strstr(morph, MORPH_DERI_SFX)) {
     mymorph.assign(morph);
     mymorph.append(" ");
@@ -3238,46 +3347,51 @@ std::string AffixMgr::morphgen(const cha
           stemmorph = mymorph.c_str();
         } else {
           stemmorph = sptr->getMorph();
         }
 
         int cmp = morphcmp(stemmorph, targetmorph);
 
         if (cmp == 0) {
-          std::string newword = sptr->add(ts, wl);
-          if (!newword.empty()) {
-            hentry* check = pHMgr->lookup(newword.c_str());  // XXX extra dic
+          char* newword = sptr->add(ts, wl);
+          if (newword) {
+            hentry* check = pHMgr->lookup(newword);  // XXX extra dic
             if (!check || !check->astr ||
                 !(TESTAFF(check->astr, forbiddenword, check->alen) ||
                   TESTAFF(check->astr, ONLYUPCASEFLAG, check->alen))) {
               return newword;
             }
+            free(newword);
           }
         }
 
         // recursive call for secondary suffixes
         if ((level == 0) && (cmp == 1) && (sptr->getContLen() > 0) &&
+            //                    (get_sfxcount(stemmorph) < targetcount) &&
             !TESTAFF(sptr->getCont(), substandard, sptr->getContLen())) {
-          std::string newword = sptr->add(ts, wl);
-          if (!newword.empty()) {
-            std::string newword2 =
-                morphgen(newword.c_str(), newword.size(), sptr->getCont(),
+          char* newword = sptr->add(ts, wl);
+          if (newword) {
+            char* newword2 =
+                morphgen(newword, strlen(newword), sptr->getCont(),
                          sptr->getContLen(), stemmorph, targetmorph, 1);
 
-            if (!newword2.empty()) {
+            if (newword2) {
+              free(newword);
               return newword2;
             }
+            free(newword);
+            newword = NULL;
           }
         }
       }
       sptr = sptr->getFlgNxt();
     }
   }
-  return std::string();
+  return NULL;
 }
 
 int AffixMgr::expand_rootword(struct guessword* wlst,
                               int maxn,
                               const char* ts,
                               int wl,
                               const unsigned short* ap,
                               unsigned short al,
@@ -3320,38 +3434,40 @@ int AffixMgr::expand_rootword(struct gue
           // check needaffix flag
           !(sptr->getCont() &&
             ((needaffix &&
               TESTAFF(sptr->getCont(), needaffix, sptr->getContLen())) ||
              (circumfix &&
               TESTAFF(sptr->getCont(), circumfix, sptr->getContLen())) ||
              (onlyincompound &&
               TESTAFF(sptr->getCont(), onlyincompound, sptr->getContLen()))))) {
-        std::string newword = sptr->add(ts, wl);
-        if (!newword.empty()) {
+        char* newword = sptr->add(ts, wl);
+        if (newword) {
           if (nh < maxn) {
-            wlst[nh].word = mystrdup(newword.c_str());
+            wlst[nh].word = newword;
             wlst[nh].allow = sptr->allowCross();
             wlst[nh].orig = NULL;
             nh++;
             // add special phonetic version
             if (phon && (nh < maxn)) {
               std::string prefix(phon);
               std::string key(sptr->getKey());
               reverseword(key);
               prefix.append(key);
               wlst[nh].word = mystrdup(prefix.c_str());
               if (!wlst[nh].word)
                 return nh - 1;
               wlst[nh].allow = (1 == 0);
-              wlst[nh].orig = mystrdup(newword.c_str());
+              wlst[nh].orig = mystrdup(newword);
               if (!wlst[nh].orig)
                 return nh - 1;
               nh++;
             }
+          } else {
+            free(newword);
           }
         }
       }
       sptr = sptr->getFlgNxt();
     }
   }
 
   int n = nh;
@@ -3363,23 +3479,25 @@ int AffixMgr::expand_rootword(struct gue
         const unsigned char c = (unsigned char)(ap[k] & 0x00FF);
         PfxEntry* cptr = pFlag[c];
         while (cptr) {
           if ((cptr->getFlag() == ap[k]) && cptr->allowCross() &&
               (!cptr->getKeyLen() ||
                ((badl > cptr->getKeyLen()) &&
                 (strncmp(cptr->getKey(), bad, cptr->getKeyLen()) == 0)))) {
             int l1 = strlen(wlst[j].word);
-            std::string newword = cptr->add(wlst[j].word, l1);
-            if (!newword.empty()) {
+            char* newword = cptr->add(wlst[j].word, l1);
+            if (newword) {
               if (nh < maxn) {
-                wlst[nh].word = mystrdup(newword.c_str());
+                wlst[nh].word = newword;
                 wlst[nh].allow = cptr->allowCross();
                 wlst[nh].orig = NULL;
                 nh++;
+              } else {
+                free(newword);
               }
             }
           }
           cptr = cptr->getFlgNxt();
         }
       }
     }
 
@@ -3395,35 +3513,44 @@ int AffixMgr::expand_rootword(struct gue
           // check needaffix flag
           !(ptr->getCont() &&
             ((needaffix &&
               TESTAFF(ptr->getCont(), needaffix, ptr->getContLen())) ||
              (circumfix &&
               TESTAFF(ptr->getCont(), circumfix, ptr->getContLen())) ||
              (onlyincompound &&
               TESTAFF(ptr->getCont(), onlyincompound, ptr->getContLen()))))) {
-        std::string newword = ptr->add(ts, wl);
-        if (!newword.empty()) {
+        char* newword = ptr->add(ts, wl);
+        if (newword) {
           if (nh < maxn) {
-            wlst[nh].word = mystrdup(newword.c_str());
+            wlst[nh].word = newword;
             wlst[nh].allow = ptr->allowCross();
             wlst[nh].orig = NULL;
             nh++;
+          } else {
+            free(newword);
           }
         }
       }
       ptr = ptr->getFlgNxt();
     }
   }
 
   return nh;
 }
 
+// return length of replacing table
+int AffixMgr::get_numrep() const {
+  return numrep;
+}
+
 // return replacing table
-const std::vector<replentry>& AffixMgr::get_reptable() const {
+struct replentry* AffixMgr::get_reptable() const {
+  if (!reptable)
+    return NULL;
   return reptable;
 }
 
 // return iconv table
 RepList* AffixMgr::get_iconvtable() const {
   if (!iconvtable)
     return NULL;
   return iconvtable;
@@ -3438,31 +3565,45 @@ RepList* AffixMgr::get_oconvtable() cons
 
 // return replacing table
 struct phonetable* AffixMgr::get_phonetable() const {
   if (!phone)
     return NULL;
   return phone;
 }
 
-// return character map table
-const std::vector<mapentry>& AffixMgr::get_maptable() const {
-  return maptable;
+// return length of character map table
+int AffixMgr::get_nummap() const {
+  return nummap;
 }
 
 // return character map table
-const std::vector<std::string>& AffixMgr::get_breaktable() const {
+struct mapentry* AffixMgr::get_maptable() const {
+  if (!maptable)
+    return NULL;
+  return maptable;
+}
+
+// return length of word break table
+int AffixMgr::get_numbreak() const {
+  return numbreak;
+}
+
+// return character map table
+char** AffixMgr::get_breaktable() const {
+  if (!breaktable)
+    return NULL;
   return breaktable;
 }
 
 // return text encoding of dictionary
-const std::string& AffixMgr::get_encoding() {
-  if (encoding.empty())
-    encoding = SPELL_ENCODING;
-  return encoding;
+char* AffixMgr::get_encoding() {
+  if (!encoding)
+    encoding = mystrdup(SPELL_ENCODING);
+  return mystrdup(encoding);
 }
 
 // return text encoding of dictionary
 int AffixMgr::get_langnum() const {
   return langnum;
 }
 
 // return double prefix option
@@ -3495,53 +3636,53 @@ int AffixMgr::get_checksharps() const {
   return checksharps;
 }
 
 char* AffixMgr::encode_flag(unsigned short aflag) const {
   return pHMgr->encode_flag(aflag);
 }
 
 // return the preferred ignore string for suggestions
-const char* AffixMgr::get_ignore() const {
-  if (ignorechars.empty())
+char* AffixMgr::get_ignore() const {
+  if (!ignorechars)
     return NULL;
-  return ignorechars.c_str();
+  return ignorechars;
 }
 
 // return the preferred ignore string for suggestions
 const std::vector<w_char>& AffixMgr::get_ignore_utf16() const {
   return ignorechars_utf16;
 }
 
 // return the keyboard string for suggestions
 char* AffixMgr::get_key_string() {
-  if (keystring.empty())
-    keystring = SPELL_KEYSTRING;
-  return mystrdup(keystring.c_str());
+  if (!keystring)
+    keystring = mystrdup(SPELL_KEYSTRING);
+  return mystrdup(keystring);
 }
 
 // return the preferred try string for suggestions
 char* AffixMgr::get_try_string() const {
-  if (trystring.empty())
+  if (!trystring)
     return NULL;
-  return mystrdup(trystring.c_str());
+  return mystrdup(trystring);
 }
 
 // return the preferred try string for suggestions
-const std::string& AffixMgr::get_wordchars() const {
+const char* AffixMgr::get_wordchars() const {
   return wordchars;
 }
 
 const std::vector<w_char>& AffixMgr::get_wordchars_utf16() const {
   return wordchars_utf16;
 }
 
 // is there compounding?
 int AffixMgr::get_compound() const {
-  return compoundflag || compoundbegin || !defcpdtable.empty();
+  return compoundflag || compoundbegin || numdefcpd;
 }
 
 // return the compound words control flag
 FLAG AffixMgr::get_compoundflag() const {
   return compoundflag;
 }
 
 // return the forbidden words control flag
@@ -3564,26 +3705,59 @@ FLAG AffixMgr::get_needaffix() const {
   return needaffix;
 }
 
 // return the onlyincompound flag
 FLAG AffixMgr::get_onlyincompound() const {
   return onlyincompound;
 }
 
+// return the compound word signal flag
+FLAG AffixMgr::get_compoundroot() const {
+  return compoundroot;
+}
+
+// return the compound begin signal flag
+FLAG AffixMgr::get_compoundbegin() const {
+  return compoundbegin;
+}
+
+// return the value of checknum
+int AffixMgr::get_checknum() const {
+  return checknum;
+}
+
+// return the value of prefix
+const char* AffixMgr::get_prefix() const {
+  if (pfx)
+    return pfx->getKey();
+  return NULL;
+}
+
 // return the value of suffix
-const std::string& AffixMgr::get_version() const {
+const char* AffixMgr::get_suffix() const {
+  return sfxappnd;
+}
+
+// return the value of suffix
+const char* AffixMgr::get_version() const {
   return version;
 }
 
+// return lemma_present flag
+FLAG AffixMgr::get_lemma_present() const {
+  return lemma_present;
+}
+
 // utility method to look up root words in hash table
 struct hentry* AffixMgr::lookup(const char* word) {
+  int i;
   struct hentry* he = NULL;
-  for (size_t i = 0; i < alldic.size() && !he; ++i) {
-    he = alldic[i]->lookup(word);
+  for (i = 0; i < *maxdic && !he; i++) {
+    he = (alldic[i])->lookup(word);
   }
   return he;
 }
 
 // return the value of suffix
 int AffixMgr::have_contclass() const {
   return havecontclass;
 }
@@ -3615,761 +3789,849 @@ int AffixMgr::get_nosplitsugs(void) cons
 }
 
 // return sugswithdots
 int AffixMgr::get_sugswithdots(void) const {
   return sugswithdots;
 }
 
 /* parse flag */
-bool AffixMgr::parse_flag(const std::string& line, unsigned short* out, FileMgr* af) {
+int AffixMgr::parse_flag(char* line, unsigned short* out, FileMgr* af) {
+  char* s = NULL;
   if (*out != FLAG_NULL && !(*out >= DEFAULTFLAGS)) {
     HUNSPELL_WARNING(
         stderr,
         "error: line %d: multiple definitions of an affix file parameter\n",
         af->getlinenum());
-    return false;
+    return 1;
   }
-  std::string s;
-  if (!parse_string(line, s, af->getlinenum()))
-    return false;
-  *out = pHMgr->decode_flag(s.c_str());
-  return true;
+  if (parse_string(line, &s, af->getlinenum()))
+    return 1;
+  *out = pHMgr->decode_flag(s);
+  free(s);
+  return 0;
 }
 
 /* parse num */
-bool AffixMgr::parse_num(const std::string& line, int* out, FileMgr* af) {
+int AffixMgr::parse_num(char* line, int* out, FileMgr* af) {
+  char* s = NULL;
   if (*out != -1) {
     HUNSPELL_WARNING(
         stderr,
         "error: line %d: multiple definitions of an affix file parameter\n",
         af->getlinenum());
-    return false;
+    return 1;
   }
-  std::string s;
-  if (!parse_string(line, s, af->getlinenum()))
-    return false;
-  *out = atoi(s.c_str());
-  return true;
+  if (parse_string(line, &s, af->getlinenum()))
+    return 1;
+  *out = atoi(s);
+  free(s);
+  return 0;
 }
 
 /* parse in the max syllablecount of compound words and  */
-bool AffixMgr::parse_cpdsyllable(const std::string& line, FileMgr* af) {
+int AffixMgr::parse_cpdsyllable(char* line, FileMgr* af) {
+  char* tp = line;
+  char* piece;
   int i = 0;
   int np = 0;
-  std::string::const_iterator iter = line.begin();
-  std::string::const_iterator start_piece = mystrsep(line, iter);
-  while (start_piece != line.end()) {
-    switch (i) {
-      case 0: {
-        np++;
-        break;
-      }
-      case 1: {
-        cpdmaxsyllable = atoi(std::string(start_piece, iter).c_str());
-        np++;
-        break;
+  piece = mystrsep(&tp, 0);
+  while (piece) {
+    if (*piece != '\0') {
+      switch (i) {
+        case 0: {
+          np++;
+          break;
+        }
+        case 1: {
+          cpdmaxsyllable = atoi(piece);
+          np++;
+          break;
+        }
+        case 2: {
+          if (!utf8) {
+            cpdvowels = mystrdup(piece);
+          } else {
+            std::vector<w_char> w;
+            u8_u16(w, piece);
+            if (!w.empty()) {
+              std::sort(w.begin(), w.end());
+              cpdvowels_utf16 = (w_char*)malloc(w.size() * sizeof(w_char));
+              if (!cpdvowels_utf16)
+                return 1;
+              memcpy(cpdvowels_utf16, &w[0], w.size());
+            }
+            cpdvowels_utf16_len = w.size();
+          }
+          np++;
+          break;
+        }
+        default:
+          break;
       }
-      case 2: {
-        if (!utf8) {
-          cpdvowels.assign(start_piece, iter);
-          std::sort(cpdvowels.begin(), cpdvowels.end());
-        } else {
-          std::string piece(start_piece, iter);
-          u8_u16(cpdvowels_utf16, piece);
-          std::sort(cpdvowels_utf16.begin(), cpdvowels_utf16.end());
-        }
-        np++;
-        break;
-      }
-      default:
-        break;
+      i++;
     }
-    ++i;
-    start_piece = mystrsep(line, iter);
+    piece = mystrsep(&tp, 0);
   }
   if (np < 2) {
     HUNSPELL_WARNING(stderr,
                      "error: line %d: missing compoundsyllable information\n",
                      af->getlinenum());
     return 1;
   }
   if (np == 2)
-    cpdvowels = "AEIOUaeiou";
+    cpdvowels = mystrdup("aeiouAEIOU");
   return 0;
 }
 
 /* parse in the typical fault correcting table */
-bool AffixMgr::parse_reptable(const std::string& line, FileMgr* af) {
-  if (parsedrep) {
+int AffixMgr::parse_reptable(char* line, FileMgr* af) {
+  if (numrep != 0) {
     HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n",
                      af->getlinenum());
-    return false;
+    return 1;
   }
-  parsedrep = true;
-  int numrep = -1;
+  char* tp = line;
+  char* piece;
   int i = 0;
   int np = 0;
-  std::string::const_iterator iter = line.begin();
-  std::string::const_iterator start_piece = mystrsep(line, iter);
-  while (start_piece != line.end()) {
-    switch (i) {
-      case 0: {
-        np++;
-        break;
-      }
-      case 1: {
-        numrep = atoi(std::string(start_piece, iter).c_str());
-        if (numrep < 1) {
-          HUNSPELL_WARNING(stderr, "error: line %d: incorrect entry number\n",
-                           af->getlinenum());
-          return false;
-        }
-        reptable.reserve(numrep);
-        np++;
-        break;
-      }
-      default:
-        break;
-    }
-    ++i;
-    start_piece = mystrsep(line, iter);
-  }
-  if (np != 2) {
-    HUNSPELL_WARNING(stderr, "error: line %d: missing data\n",
-                     af->getlinenum());
-    return false;
-  }
-
-  /* now parse the numrep lines to read in the remainder of the table */
-  for (int j = 0; j < numrep; ++j) {
-    std::string nl;
-    if (!af->getline(nl))
-      return false;
-    mychomp(nl);
-    reptable.push_back(replentry());
-    iter = nl.begin();
-    i = 0;
-    int type = 0;
-    start_piece = mystrsep(nl, iter);
-    while (start_piece != nl.end()) {
+  piece = mystrsep(&tp, 0);
+  while (piece) {
+    if (*piece != '\0') {
       switch (i) {
         case 0: {
-          if (nl.compare(start_piece - nl.begin(), 3, "REP", 3) != 0) {
-            HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
-                             af->getlinenum());
-            reptable.clear();
-            return false;
-          }
+          np++;
           break;
         }
         case 1: {
-          if (*start_piece == '^')
-            type = 1;
-          reptable.back().pattern.assign(start_piece + type, iter);
-          mystrrep(reptable.back().pattern, "_", " ");
-          if (!reptable.back().pattern.empty() && reptable.back().pattern[reptable.back().pattern.size() - 1] == '$') {
-            type += 2;
-            reptable.back().pattern.resize(reptable.back().pattern.size() - 1);
+          numrep = atoi(piece);
+          if (numrep < 1) {
+            HUNSPELL_WARNING(stderr, "error: line %d: incorrect entry number\n",
+                             af->getlinenum());
+            return 1;
           }
-          break;
-        }
-        case 2: {
-          reptable.back().outstrings[type].assign(start_piece, iter);
-          mystrrep(reptable.back().outstrings[type], "_", " ");
+          reptable = (replentry*)malloc(numrep * sizeof(struct replentry));
+          if (!reptable)
+            return 1;
+          np++;
           break;
         }
         default:
           break;
       }
-      ++i;
-      start_piece = mystrsep(nl, iter);
-    }
-    if (reptable.back().pattern.empty() || reptable.back().outstrings[type].empty()) {
-      HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
-                       af->getlinenum());
-      reptable.clear();
-      return false;
+      i++;
     }
-  }
-  return true;
-}
-
-/* parse in the typical fault correcting table */
-bool AffixMgr::parse_convtable(const std::string& line,
-                              FileMgr* af,
-                              RepList** rl,
-                              const std::string& keyword) {
-  if (*rl) {
-    HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n",
-                     af->getlinenum());
-    return false;
-  }
-  int i = 0;
-  int np = 0;
-  int numrl = 0;
-  std::string::const_iterator iter = line.begin();
-  std::string::const_iterator start_piece = mystrsep(line, iter);
-  while (start_piece != line.end()) {
-    switch (i) {
-      case 0: {
-        np++;
-        break;
-      }
-      case 1: {
-        numrl = atoi(std::string(start_piece, iter).c_str());
-        if (numrl < 1) {
-          HUNSPELL_WARNING(stderr, "error: line %d: incorrect entry number\n",
-                           af->getlinenum());
-          return false;
-        }
-        *rl = new RepList(numrl);
-        if (!*rl)
-          return false;
-        np++;
-        break;
-      }
-      default:
-        break;
-    }
-    ++i;
-    start_piece = mystrsep(line, iter);
+    piece = mystrsep(&tp, 0);
   }
   if (np != 2) {
     HUNSPELL_WARNING(stderr, "error: line %d: missing data\n",
                      af->getlinenum());
-    return false;
+    return 1;
   }
 
-  /* now parse the num lines to read in the remainder of the table */
-  for (int j = 0; j < numrl; j++) {
-    std::string nl;
-    if (!af->getline(nl))
-      return false;
+  /* now parse the numrep lines to read in the remainder of the table */
+  char* nl;
+  for (int j = 0; j < numrep; j++) {
+    if ((nl = af->getline()) == NULL)
+      return 1;
     mychomp(nl);
+    tp = nl;
     i = 0;
-    std::string pattern;
-    std::string pattern2;
-    iter = nl.begin();
-    start_piece = mystrsep(nl, iter);
-    while (start_piece != nl.end()) {
-      {
+    reptable[j].pattern = NULL;
+    reptable[j].pattern2 = NULL;
+    piece = mystrsep(&tp, 0);
+    while (piece) {
+      if (*piece != '\0') {
         switch (i) {
           case 0: {
-            if (nl.compare(start_piece - nl.begin(), keyword.size(), keyword, 0, keyword.size()) != 0) {
+            if (strncmp(piece, "REP", 3) != 0) {
               HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
                                af->getlinenum());
-              delete *rl;
-              *rl = NULL;
-              return false;
+              numrep = 0;
+              return 1;
             }
             break;
           }
           case 1: {
-            pattern.assign(start_piece, iter);
+            if (*piece == '^')
+              reptable[j].start = true;
+            else
+              reptable[j].start = false;
+            reptable[j].pattern =
+                mystrrep(mystrdup(piece + int(reptable[j].start)), "_", " ");
+            int lr = strlen(reptable[j].pattern) - 1;
+            if (reptable[j].pattern[lr] == '$') {
+              reptable[j].end = true;
+              reptable[j].pattern[lr] = '\0';
+            } else
+              reptable[j].end = false;
             break;
           }
           case 2: {
-            pattern2.assign(start_piece, iter);
+            reptable[j].pattern2 = mystrrep(mystrdup(piece), "_", " ");
             break;
           }
           default:
             break;
         }
-        ++i;
+        i++;
       }
-      start_piece = mystrsep(nl, iter);
+      piece = mystrsep(&tp, 0);
     }
-    if (pattern.empty() || pattern2.empty()) {
+    if ((!(reptable[j].pattern)) || (!(reptable[j].pattern2))) {
       HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
                        af->getlinenum());
-      return false;
+      numrep = 0;
+      return 1;
     }
-    (*rl)->add(pattern, pattern2);
   }
-  return true;
+  return 0;
 }
 
 /* parse in the typical fault correcting table */
-bool AffixMgr::parse_phonetable(const std::string& line, FileMgr* af) {
-  if (phone) {
+int AffixMgr::parse_convtable(char* line,
+                              FileMgr* af,
+                              RepList** rl,
+                              const char* keyword) {
+  if (*rl) {
     HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n",
                      af->getlinenum());
-    return false;
+    return 1;
   }
-  int num = -1;
+  char* tp = line;
+  char* piece;
   int i = 0;
   int np = 0;
-  std::string::const_iterator iter = line.begin();
-  std::string::const_iterator start_piece = mystrsep(line, iter);
-  while (start_piece != line.end()) {
-    switch (i) {
-      case 0: {
-        np++;
-        break;
+  int numrl = 0;
+  piece = mystrsep(&tp, 0);
+  while (piece) {
+    if (*piece != '\0') {
+      switch (i) {
+        case 0: {
+          np++;
+          break;
+        }
+        case 1: {
+          numrl = atoi(piece);
+          if (numrl < 1) {
+            HUNSPELL_WARNING(stderr, "error: line %d: incorrect entry number\n",
+                             af->getlinenum());
+            return 1;
+          }
+          *rl = new RepList(numrl);
+          if (!*rl)
+            return 1;
+          np++;
+          break;
+        }
+        default:
+          break;
       }
-      case 1: {
-        num = atoi(std::string(start_piece, iter).c_str());
-        if (num < 1) {
-          HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
-                           af->getlinenum());
-          return false;
-        }
-        phone = new phonetable;
-        phone->utf8 = (char)utf8;
-        np++;
-        break;
-      }
-      default:
-        break;
+      i++;
     }
-    ++i;
-    start_piece = mystrsep(line, iter);
+    piece = mystrsep(&tp, 0);
   }
   if (np != 2) {
     HUNSPELL_WARNING(stderr, "error: line %d: missing data\n",
                      af->getlinenum());
-    return false;
+    return 1;
   }
 
-  /* now parse the phone->num lines to read in the remainder of the table */
-  for (int j = 0; j < num; ++j) {
-    std::string nl;
-    if (!af->getline(nl))
-      return false;
+  /* now parse the num lines to read in the remainder of the table */
+  char* nl;
+  for (int j = 0; j < numrl; j++) {
+    if (!(nl = af->getline()))
+      return 1;
     mychomp(nl);
+    tp = nl;
     i = 0;
-    const size_t old_size = phone->rules.size();
-    iter = nl.begin();
-    start_piece = mystrsep(nl, iter);
-    while (start_piece != nl.end()) {
-      {
+    char* pattern = NULL;
+    char* pattern2 = NULL;
+    piece = mystrsep(&tp, 0);
+    while (piece) {
+      if (*piece != '\0') {
         switch (i) {
           case 0: {
-            if (nl.compare(start_piece - nl.begin(), 5, "PHONE", 5) != 0) {
+            if (strncmp(piece, keyword, strlen(keyword)) != 0) {
               HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
                                af->getlinenum());
-              return false;
+              delete *rl;
+              *rl = NULL;
+              return 1;
             }
             break;
           }
           case 1: {
-            phone->rules.push_back(std::string(start_piece, iter));
+            pattern = mystrrep(mystrdup(piece), "_", " ");
             break;
           }
           case 2: {
-            phone->rules.push_back(std::string(start_piece, iter));
-            mystrrep(phone->rules.back(), "_", "");
+            pattern2 = mystrrep(mystrdup(piece), "_", " ");
             break;
           }
           default:
             break;
         }
-        ++i;
+        i++;
       }
-      start_piece = mystrsep(nl, iter);
+      piece = mystrsep(&tp, 0);
     }
-    if (phone->rules.size() != old_size + 2) {
+    if (!pattern || !pattern2) {
+      if (pattern)
+        free(pattern);
+      if (pattern2)
+        free(pattern2);
       HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
                        af->getlinenum());
-      phone->rules.clear();
-      return false;
+      return 1;
     }
+    (*rl)->add(pattern, pattern2);
   }
-  phone->rules.push_back("");
-  phone->rules.push_back("");
-  init_phonet_hash(*phone);
-  return true;
+  return 0;
 }
 
-/* parse in the checkcompoundpattern table */
-bool AffixMgr::parse_checkcpdtable(const std::string& line, FileMgr* af) {
-  if (parsedcheckcpd) {
+/* parse in the typical fault correcting table */
+int AffixMgr::parse_phonetable(char* line, FileMgr* af) {
+  if (phone) {
     HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n",
                      af->getlinenum());
-    return false;
+    return 1;
   }
-  parsedcheckcpd = true;
-  int numcheckcpd = -1;
+  char* tp = line;
+  char* piece;
   int i = 0;
   int np = 0;
-  std::string::const_iterator iter = line.begin();
-  std::string::const_iterator start_piece = mystrsep(line, iter);
-  while (start_piece != line.end()) {
-    switch (i) {
-      case 0: {
-        np++;
-        break;
+  piece = mystrsep(&tp, 0);
+  while (piece) {
+    if (*piece != '\0') {
+      switch (i) {
+        case 0: {
+          np++;
+          break;
+        }
+        case 1: {
+          phone = (phonetable*)malloc(sizeof(struct phonetable));
+          if (!phone)
+            return 1;
+          phone->num = atoi(piece);
+          phone->rules = NULL;
+          phone->utf8 = (char)utf8;
+          if (phone->num < 1) {
+            HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
+                             af->getlinenum());
+            return 1;
+          }
+          phone->rules = (char**)malloc(2 * (phone->num + 1) * sizeof(char*));
+          if (!phone->rules) {
+            free(phone);
+            phone = NULL;
+            return 1;
+          }
+          np++;
+          break;
+        }
+        default:
+          break;
       }
-      case 1: {
-        numcheckcpd = atoi(std::string(start_piece, iter).c_str());
-        if (numcheckcpd < 1) {
-          HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
-                           af->getlinenum());
-          return false;
-        }
-        checkcpdtable.reserve(numcheckcpd);
-        np++;
-        break;
-      }
-      default:
-        break;
+      i++;
     }
-    ++i;
-    start_piece = mystrsep(line, iter);
+    piece = mystrsep(&tp, 0);
   }
   if (np != 2) {
     HUNSPELL_WARNING(stderr, "error: line %d: missing data\n",
                      af->getlinenum());
-    return false;
+    return 1;
   }
 
-  /* now parse the numcheckcpd lines to read in the remainder of the table */
-  for (int j = 0; j < numcheckcpd; ++j) {
-    std::string nl;
-    if (!af->getline(nl))
-      return false;
+  /* now parse the phone->num lines to read in the remainder of the table */
+  char* nl;
+  for (int j = 0; j < phone->num; j++) {
+    if (!(nl = af->getline()))
+      return 1;
     mychomp(nl);
+    tp = nl;
     i = 0;
-    checkcpdtable.push_back(patentry());
-    iter = nl.begin();
-    start_piece = mystrsep(nl, iter);
-    while (start_piece != nl.end()) {
+    phone->rules[j * 2] = NULL;
+    phone->rules[j * 2 + 1] = NULL;
+    piece = mystrsep(&tp, 0);
+    while (piece) {
+      if (*piece != '\0') {
+        switch (i) {
+          case 0: {
+            if (strncmp(piece, "PHONE", 5) != 0) {
+              HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
+                               af->getlinenum());
+              phone->num = 0;
+              return 1;
+            }
+            break;
+          }
+          case 1: {
+            phone->rules[j * 2] = mystrrep(mystrdup(piece), "_", "");
+            break;
+          }
+          case 2: {
+            phone->rules[j * 2 + 1] = mystrrep(mystrdup(piece), "_", "");
+            break;
+          }
+          default:
+            break;
+        }
+        i++;
+      }
+      piece = mystrsep(&tp, 0);
+    }
+    if ((!(phone->rules[j * 2])) || (!(phone->rules[j * 2 + 1]))) {
+      HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
+                       af->getlinenum());
+      phone->num = 0;
+      return 1;
+    }
+  }
+  phone->rules[phone->num * 2] = mystrdup("");
+  phone->rules[phone->num * 2 + 1] = mystrdup("");
+  init_phonet_hash(*phone);
+  return 0;
+}
+
+/* parse in the checkcompoundpattern table */
+int AffixMgr::parse_checkcpdtable(char* line, FileMgr* af) {
+  if (numcheckcpd != 0) {
+    HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n",
+                     af->getlinenum());
+    return 1;
+  }
+  char* tp = line;
+  char* piece;
+  int i = 0;
+  int np = 0;
+  piece = mystrsep(&tp, 0);
+  while (piece) {
+    if (*piece != '\0') {
       switch (i) {
         case 0: {
-          if (nl.compare(start_piece - nl.begin(), 20, "CHECKCOMPOUNDPATTERN", 20) != 0) {
-            HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
-                             af->getlinenum());
-            return false;
-          }
+          np++;
           break;
         }
         case 1: {
-          checkcpdtable.back().pattern.assign(start_piece, iter);
-          size_t slash_pos = checkcpdtable.back().pattern.find('/');
-          if (slash_pos != std::string::npos) {
-            std::string chunk(checkcpdtable.back().pattern, slash_pos + 1);
-            checkcpdtable.back().pattern.resize(slash_pos);
-            checkcpdtable.back().cond = pHMgr->decode_flag(chunk.c_str());
+          numcheckcpd = atoi(piece);
+          if (numcheckcpd < 1) {
+            HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
+                             af->getlinenum());
+            return 1;
           }
-          break;
-        }
-        case 2: {
-          checkcpdtable.back().pattern2.assign(start_piece, iter);
-          size_t slash_pos = checkcpdtable.back().pattern2.find('/');
-          if (slash_pos != std::string::npos) {
-            std::string chunk(checkcpdtable.back().pattern2, slash_pos + 1);
-            checkcpdtable.back().pattern2.resize(slash_pos);
-            checkcpdtable.back().cond2 = pHMgr->decode_flag(chunk.c_str());
-          }
-          break;
-        }
-        case 3: {
-          checkcpdtable.back().pattern3.assign(start_piece, iter);
-          simplifiedcpd = 1;
+          checkcpdtable =
+              (patentry*)malloc(numcheckcpd * sizeof(struct patentry));
+          if (!checkcpdtable)
+            return 1;
+          np++;
           break;
         }
         default:
           break;
       }
       i++;
-      start_piece = mystrsep(nl, iter);
     }
-  }
-  return true;
-}
-
-/* parse in the compound rule table */
-bool AffixMgr::parse_defcpdtable(const std::string& line, FileMgr* af) {
-  if (parseddefcpd) {
-    HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n",
-                     af->getlinenum());
-    return false;
-  }
-  parseddefcpd = true;
-  int numdefcpd = -1;
-  int i = 0;
-  int np = 0;
-  std::string::const_iterator iter = line.begin();
-  std::string::const_iterator start_piece = mystrsep(line, iter);
-  while (start_piece != line.end()) {
-    switch (i) {
-      case 0: {
-        np++;
-        break;
-      }
-      case 1: {
-        numdefcpd = atoi(std::string(start_piece, iter).c_str());
-        if (numdefcpd < 1) {
-          HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
-                           af->getlinenum());
-          return false;
-        }
-        defcpdtable.reserve(numdefcpd);
-        np++;
-        break;
-      }
-      default:
-        break;
-    }
-    ++i;
-    start_piece = mystrsep(line, iter);
+    piece = mystrsep(&tp, 0);
   }
   if (np != 2) {
     HUNSPELL_WARNING(stderr, "error: line %d: missing data\n",
                      af->getlinenum());
-    return false;
+    return 1;
   }
 
-  /* now parse the numdefcpd lines to read in the remainder of the table */
-  for (int j = 0; j < numdefcpd; ++j) {
-    std::string nl;
-    if (!af->getline(nl))
-      return false;
+  /* now parse the numcheckcpd lines to read in the remainder of the table */
+  char* nl;
+  for (int j = 0; j < numcheckcpd; j++) {
+    if (!(nl = af->getline()))
+      return 1;
     mychomp(nl);
+    tp = nl;
     i = 0;
-    defcpdtable.push_back(flagentry());
-    iter = nl.begin();
-    start_piece = mystrsep(nl, iter);
-    while (start_piece != nl.end()) {
+    checkcpdtable[j].pattern = NULL;
+    checkcpdtable[j].pattern2 = NULL;
+    checkcpdtable[j].pattern3 = NULL;
+    checkcpdtable[j].cond = FLAG_NULL;
+    checkcpdtable[j].cond2 = FLAG_NULL;
+    piece = mystrsep(&tp, 0);
+    while (piece) {
+      if (*piece != '\0') {
+        switch (i) {
+          case 0: {
+            if (strncmp(piece, "CHECKCOMPOUNDPATTERN", 20) != 0) {
+              HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
+                               af->getlinenum());
+              numcheckcpd = 0;
+              return 1;
+            }
+            break;
+          }
+          case 1: {
+            checkcpdtable[j].pattern = mystrdup(piece);
+            char* p = strchr(checkcpdtable[j].pattern, '/');
+            if (p) {
+              *p = '\0';
+              checkcpdtable[j].cond = pHMgr->decode_flag(p + 1);
+            }
+            break;
+          }
+          case 2: {
+            checkcpdtable[j].pattern2 = mystrdup(piece);
+            char* p = strchr(checkcpdtable[j].pattern2, '/');
+            if (p) {
+              *p = '\0';
+              checkcpdtable[j].cond2 = pHMgr->decode_flag(p + 1);
+            }
+            break;
+          }
+          case 3: {
+            checkcpdtable[j].pattern3 = mystrdup(piece);
+            simplifiedcpd = 1;
+            break;
+          }
+          default:
+            break;
+        }
+        i++;
+      }
+      piece = mystrsep(&tp, 0);
+    }
+    if ((!(checkcpdtable[j].pattern)) || (!(checkcpdtable[j].pattern2))) {
+      HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
+                       af->getlinenum());
+      numcheckcpd = 0;
+      return 1;
+    }
+  }
+  return 0;
+}
+
+/* parse in the compound rule table */
+int AffixMgr::parse_defcpdtable(char* line, FileMgr* af) {
+  if (numdefcpd != 0) {
+    HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n",
+                     af->getlinenum());
+    return 1;
+  }
+  char* tp = line;
+  char* piece;
+  int i = 0;
+  int np = 0;
+  piece = mystrsep(&tp, 0);
+  while (piece) {
+    if (*piece != '\0') {
       switch (i) {
         case 0: {
-          if (nl.compare(start_piece - nl.begin(), 12, "COMPOUNDRULE", 12) != 0) {
-            HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
-                             af->getlinenum());
-            numdefcpd = 0;
-            return false;
-          }
+          np++;
           break;
         }
-        case 1: {  // handle parenthesized flags
-          if (std::find(start_piece, iter, '(') != iter) {
-            for (std::string::const_iterator k = start_piece; k != iter; ++k) {
-              std::string::const_iterator chb = k;
-              std::string::const_iterator che = k + 1;
-              if (*k == '(') {
-                std::string::const_iterator parpos = std::find(k, iter, ')');
-                if (parpos != iter) {
-                  chb = k + 1;
-                  che = parpos;
-                  k = parpos;
-                }
-              }
-
-              if (*chb == '*' || *chb == '?') {
-                defcpdtable.back().push_back((FLAG)*chb);
-              } else {
-                pHMgr->decode_flags(defcpdtable.back(), std::string(chb, che), af);
-              }
-            }
-          } else {
-            pHMgr->decode_flags(defcpdtable.back(), std::string(start_piece, iter), af);
+        case 1: {
+          numdefcpd = atoi(piece);
+          if (numdefcpd < 1) {
+            HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
+                             af->getlinenum());
+            return 1;
           }
+          defcpdtable = (flagentry*)malloc(numdefcpd * sizeof(flagentry));
+          if (!defcpdtable)
+            return 1;
+          np++;
           break;
         }
         default:
           break;
       }
-      ++i;
-      start_piece = mystrsep(nl, iter);
-    }
-    if (defcpdtable.back().empty()) {
-      HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
-                       af->getlinenum());
-      return false;
+      i++;
     }
-  }
-  return true;
-}
-
-/* parse in the character map table */
-bool AffixMgr::parse_maptable(const std::string& line, FileMgr* af) {
-  if (parsedmaptable) {
-    HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n",
-                     af->getlinenum());
-    return false;
-  }
-  parsedmaptable = true;
-  int nummap = -1;
-  int i = 0;
-  int np = 0;
-  std::string::const_iterator iter = line.begin();
-  std::string::const_iterator start_piece = mystrsep(line, iter);
-  while (start_piece != line.end()) {
-    switch (i) {
-      case 0: {
-        np++;
-        break;
-      }
-      case 1: {
-        nummap = atoi(std::string(start_piece, iter).c_str());
-        if (nummap < 1) {
-          HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
-                           af->getlinenum());
-          return false;
-        }
-        maptable.reserve(nummap);
-        np++;
-        break;
-      }
-      default:
-        break;
-    }
-    ++i;
-    start_piece = mystrsep(line, iter);
+    piece = mystrsep(&tp, 0);
   }
   if (np != 2) {
     HUNSPELL_WARNING(stderr, "error: line %d: missing data\n",
                      af->getlinenum());
-    return false;
+    return 1;
   }
 
-  /* now parse the nummap lines to read in the remainder of the table */
-  for (int j = 0; j < nummap; ++j) {
-    std::string nl;
-    if (!af->getline(nl))
-      return false;
+  /* now parse the numdefcpd lines to read in the remainder of the table */
+  char* nl;
+  for (int j = 0; j < numdefcpd; j++) {
+    if (!(nl = af->getline()))
+      return 1;
     mychomp(nl);
+    tp = nl;
     i = 0;
-    maptable.push_back(mapentry());
-    iter = nl.begin();
-    start_piece = mystrsep(nl, iter);
-    while (start_piece != nl.end()) {
+    defcpdtable[j].def = NULL;
+    defcpdtable[j].len = 0;
+    piece = mystrsep(&tp, 0);
+    while (piece) {
+      if (*piece != '\0') {
+        switch (i) {
+          case 0: {
+            if (strncmp(piece, "COMPOUNDRULE", 12) != 0) {
+              HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
+                               af->getlinenum());
+              numdefcpd = 0;
+              return 1;
+            }
+            break;
+          }
+          case 1: {  // handle parenthesized flags
+            if (strchr(piece, '(')) {
+              defcpdtable[j].def = (FLAG*)malloc(strlen(piece) * sizeof(FLAG));
+              defcpdtable[j].len = 0;
+              int end = 0;
+              FLAG* conv;
+              while (!end) {
+                char* par = piece + 1;
+                while (*par != '(' && *par != ')' && *par != '\0')
+                  par++;
+                if (*par == '\0')
+                  end = 1;
+                else
+                  *par = '\0';
+                if (*piece == '(')
+                  piece++;
+                if (*piece == '*' || *piece == '?') {
+                  defcpdtable[j].def[defcpdtable[j].len++] = (FLAG)*piece;
+                } else if (*piece != '\0') {
+                  int l = pHMgr->decode_flags(&conv, piece, af);
+                  for (int k = 0; k < l; k++)
+                    defcpdtable[j].def[defcpdtable[j].len++] = conv[k];
+                  free(conv);
+                }
+                piece = par + 1;
+              }
+            } else {
+              defcpdtable[j].len =
+                  pHMgr->decode_flags(&(defcpdtable[j].def), piece, af);
+            }
+            break;
+          }
+          default:
+            break;
+        }
+        i++;
+      }
+      piece = mystrsep(&tp, 0);
+    }
+    if (!defcpdtable[j].len) {
+      HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
+                       af->getlinenum());
+      numdefcpd = 0;
+      return 1;
+    }
+  }
+  return 0;
+}
+
+/* parse in the character map table */
+int AffixMgr::parse_maptable(char* line, FileMgr* af) {
+  if (nummap != 0) {
+    HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n",
+                     af->getlinenum());
+    return 1;
+  }
+  char* tp = line;
+  char* piece;
+  int i = 0;
+  int np = 0;
+  piece = mystrsep(&tp, 0);
+  while (piece) {
+    if (*piece != '\0') {
       switch (i) {
         case 0: {
-          if (nl.compare(start_piece - nl.begin(), 3, "MAP", 3) != 0) {
-            HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
-                             af->getlinenum());
-            nummap = 0;
-            return false;
-          }
+          np++;
           break;
         }
         case 1: {
-          for (std::string::const_iterator k = start_piece; k != iter; ++k) {
-            std::string::const_iterator chb = k;
-            std::string::const_iterator che = k + 1;
-            if (*k == '(') {
-              std::string::const_iterator parpos = std::find(k, iter, ')');
-              if (parpos != iter) {
-                chb = k + 1;
-                che = parpos;
-                k = parpos;
-              }
-            } else {
-              if (utf8 && (*k & 0xc0) == 0xc0) {
-                ++k;
-                while (k != iter && (*k & 0xc0) == 0x80)
-                    ++k;
-                che = k;
-                --k;
-              }
-            }
-            maptable.back().push_back(std::string(chb, che));
+          nummap = atoi(piece);
+          if (nummap < 1) {
+            HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
+                             af->getlinenum());
+            return 1;
           }
+          maptable = (mapentry*)malloc(nummap * sizeof(struct mapentry));
+          if (!maptable)
+            return 1;
+          np++;
           break;
         }
         default:
           break;
       }
-      ++i;
-      start_piece = mystrsep(nl, iter);
-    }
-    if (maptable.back().empty()) {
-      HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
-                       af->getlinenum());
-      return false;
+      i++;
     }
-  }
-  return true;
-}
-
-/* parse in the word breakpoint table */
-bool AffixMgr::parse_breaktable(const std::string& line, FileMgr* af) {
-  if (parsedbreaktable) {
-    HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n",
-                     af->getlinenum());
-    return false;
-  }
-  parsedbreaktable = true;
-  int numbreak = -1;
-  int i = 0;
-  int np = 0;
-  std::string::const_iterator iter = line.begin();
-  std::string::const_iterator start_piece = mystrsep(line, iter);
-  while (start_piece != line.end()) {
-    switch (i) {
-      case 0: {
-        np++;
-        break;
-      }
-      case 1: {
-        numbreak = atoi(std::string(start_piece, iter).c_str());
-        if (numbreak < 0) {
-          HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
-                           af->getlinenum());
-          return false;
-        }
-        if (numbreak == 0)
-          return true;
-        breaktable.reserve(numbreak);
-        np++;
-        break;
-      }
-      default:
-        break;
-    }
-    ++i;
-    start_piece = mystrsep(line, iter);
+    piece = mystrsep(&tp, 0);
   }
   if (np != 2) {
     HUNSPELL_WARNING(stderr, "error: line %d: missing data\n",
                      af->getlinenum());
-    return false;
+    return 1;
   }
 
-  /* now parse the numbreak lines to read in the remainder of the table */
-  for (int j = 0; j < numbreak; ++j) {
-    std::string nl;
-    if (!af->getline(nl))
-      return false;
+  /* now parse the nummap lines to read in the remainder of the table */
+  char* nl;
+  for (int j = 0; j < nummap; j++) {
+    if (!(nl = af->getline()))
+      return 1;
     mychomp(nl);
+    tp = nl;
     i = 0;
-    iter = nl.begin();
-    start_piece = mystrsep(nl, iter);
-    while (start_piece != nl.end()) {
+    maptable[j].set = NULL;
+    maptable[j].len = 0;
+    piece = mystrsep(&tp, 0);
+    while (piece) {
+      if (*piece != '\0') {
+        switch (i) {
+          case 0: {
+            if (strncmp(piece, "MAP", 3) != 0) {
+              HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
+                               af->getlinenum());
+              nummap = 0;
+              return 1;
+            }
+            break;
+          }
+          case 1: {
+            int setn = 0;
+            maptable[j].len = strlen(piece);
+            maptable[j].set = (char**)malloc(maptable[j].len * sizeof(char*));
+            if (!maptable[j].set)
+              return 1;
+            for (int k = 0; k < maptable[j].len; k++) {
+              int chl = 1;
+              int chb = k;
+              if (piece[k] == '(') {
+                char* parpos = strchr(piece + k, ')');
+                if (parpos != NULL) {
+                  chb = k + 1;
+                  chl = (int)(parpos - piece) - k - 1;
+                  k = k + chl + 1;
+                }
+              } else {
+                if (utf8 && (piece[k] & 0xc0) == 0xc0) {
+                  for (k++; utf8 && (piece[k] & 0xc0) == 0x80; k++)
+                    ;
+                  chl = k - chb;
+                  k--;
+                }
+              }
+              maptable[j].set[setn] = (char*)malloc(chl + 1);
+              if (!maptable[j].set[setn])
+                return 1;
+              strncpy(maptable[j].set[setn], piece + chb, chl);
+              maptable[j].set[setn][chl] = '\0';
+              setn++;
+            }
+            maptable[j].len = setn;
+            break;
+          }
+          default:
+            break;
+        }
+        i++;
+      }
+      piece = mystrsep(&tp, 0);
+    }
+    if (!maptable[j].set || !maptable[j].len) {
+      HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
+                       af->getlinenum());
+      nummap = 0;
+      return 1;
+    }
+  }
+  return 0;
+}
+
+/* parse in the word breakpoint table */
+int AffixMgr::parse_breaktable(char* line, FileMgr* af) {
+  if (numbreak > -1) {
+    HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n",
+                     af->getlinenum());
+    return 1;
+  }
+  char* tp = line;
+  char* piece;
+  int i = 0;
+  int np = 0;
+  piece = mystrsep(&tp, 0);
+  while (piece) {
+    if (*piece != '\0') {
       switch (i) {
         case 0: {
-          if (nl.compare(start_piece - nl.begin(), 5, "BREAK", 5) != 0) {
-            HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
-                             af->getlinenum());
-            numbreak = 0;
-            return false;
-          }
+          np++;
           break;
         }
         case 1: {
-          breaktable.push_back(std::string(start_piece, iter));
+          numbreak = atoi(piece);
+          if (numbreak < 0) {
+            HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
+                             af->getlinenum());
+            return 1;
+          }
+          if (numbreak == 0)
+            return 0;
+          breaktable = (char**)malloc(numbreak * sizeof(char*));
+          if (!breaktable)
+            return 1;
+          np++;
           break;
         }
         default:
           break;
       }
-      ++i;
-      start_piece = mystrsep(nl, iter);
+      i++;
+    }
+    piece = mystrsep(&tp, 0);
+  }
+  if (np != 2) {
+    HUNSPELL_WARNING(stderr, "error: line %d: missing data\n",
+                     af->getlinenum());
+    return 1;
+  }
+
+  /* now parse the numbreak lines to read in the remainder of the table */
+  char* nl;
+  for (int j = 0; j < numbreak; j++) {
+    if (!(nl = af->getline()))
+      return 1;
+    mychomp(nl);
+    tp = nl;
+    i = 0;
+    piece = mystrsep(&tp, 0);
+    while (piece) {
+      if (*piece != '\0') {
+        switch (i) {
+          case 0: {
+            if (strncmp(piece, "BREAK", 5) != 0) {
+              HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
+                               af->getlinenum());
+              numbreak = 0;
+              return 1;
+            }
+            break;
+          }
+          case 1: {
+            breaktable[j] = mystrdup(piece);
+            break;
+          }
+          default:
+            break;
+        }
+        i++;
+      }
+      piece = mystrsep(&tp, 0);
+    }
+    if (!breaktable) {
+      HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
+                       af->getlinenum());
+      numbreak = 0;
+      return 1;
     }
   }
-
-  if (breaktable.size() != static_cast<size_t>(numbreak)) {
-    HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
-                     af->getlinenum());
-    return false;
-  }
-
-  return true;
+  return 0;
 }
 
 void AffixMgr::reverse_condition(std::string& piece) {
   if (piece.empty())
       return;
 
   int neg = 0;
   for (std::string::reverse_iterator k = piece.rbegin(); k != piece.rend(); ++k) {
@@ -4398,356 +4660,314 @@ void AffixMgr::reverse_condition(std::st
       default: {
         if (neg)
           *(k - 1) = *k;
       }
     }
   }
 }
 
-class entries_container {
-  std::vector<AffEntry*> entries;
-  AffixMgr* m_mgr;
-  char m_at;
-public:
-  entries_container(char at, AffixMgr* mgr)
-    : m_mgr(mgr)
-    , m_at(at) {
-  }
-  void release() {
-    entries.clear();
-  }
-  void initialize(int numents,
-                  char opts, unsigned short aflag) {
-    entries.reserve(numents);
-
-    if (m_at == 'P') {
-      entries.push_back(new PfxEntry(m_mgr));
-    } else {
-      entries.push_back(new SfxEntry(m_mgr));
-    }
-
-    entries.back()->opts = opts;
-    entries.back()->aflag = aflag;
-  }
-
-  AffEntry* add_entry(char opts) {
-    if (m_at == 'P') {
-      entries.push_back(new PfxEntry(m_mgr));
-    } else {
-      entries.push_back(new SfxEntry(m_mgr));
-    }
-    AffEntry* ret = entries.back();
-    ret->opts = entries[0]->opts & opts;
-    return ret;
-  }
-
-  AffEntry* first_entry() {
-    return entries.empty() ? NULL : entries[0];
-  }
-
-  ~entries_container() {
-    for (size_t i = 0; i < entries.size(); ++i) {
-        delete entries[i];
-    }
-  }
-
-  std::vector<AffEntry*>::iterator begin() { return entries.begin(); }
-  std::vector<AffEntry*>::iterator end() { return entries.end(); }
-};
-
-bool AffixMgr::parse_affix(const std::string& line,
+int AffixMgr::parse_affix(char* line,
                           const char at,
                           FileMgr* af,
                           char* dupflags) {
-  int numents = 0;  // number of AffEntry structures to parse
+  int numents = 0;  // number of affentry structures to parse
 
   unsigned short aflag = 0;  // affix char identifier
 
   char ff = 0;
-  entries_container affentries(at, this);
-
+  std::vector<affentry> affentries;
+
+  char* tp = line;
+  char* nl = line;
+  char* piece;
   int i = 0;
 
 // checking lines with bad syntax
 #ifdef DEBUG
   int basefieldnum = 0;
 #endif
 
   // split affix header line into pieces
 
   int np = 0;
-  std::string::const_iterator iter = line.begin();
-  std::string::const_iterator start_piece = mystrsep(line, iter);
-  while (start_piece != line.end()) {
-    switch (i) {
-      // piece 1 - is type of affix
-      case 0: {
-        np++;
-        break;
-      }
-
-      // piece 2 - is affix char
-      case 1: {
-        np++;
-        aflag = pHMgr->decode_flag(std::string(start_piece, iter).c_str());
-        if (((at == 'S') && (dupflags[aflag] & dupSFX)) ||
-            ((at == 'P') && (dupflags[aflag] & dupPFX))) {
-          HUNSPELL_WARNING(
-              stderr,
-              "error: line %d: multiple definitions of an affix flag\n",
-              af->getlinenum());
+
+  piece = mystrsep(&tp, 0);
+  while (piece) {
+    if (*piece != '\0') {
+      switch (i) {
+        // piece 1 - is type of affix
+        case 0: {
+          np++;
+          break;
+        }
+
+        // piece 2 - is affix char
+        case 1: {
+          np++;
+          aflag = pHMgr->decode_flag(piece);
+          if (((at == 'S') && (dupflags[aflag] & dupSFX)) ||
+              ((at == 'P') && (dupflags[aflag] & dupPFX))) {
+            HUNSPELL_WARNING(
+                stderr,
+                "error: line %d: multiple definitions of an affix flag\n",
+                af->getlinenum());
+            // return 1; XXX permissive mode for bad dictionaries
+          }
+          dupflags[aflag] += (char)((at == 'S') ? dupSFX : dupPFX);
+          break;
         }
-        dupflags[aflag] += (char)((at == 'S') ? dupSFX : dupPFX);
-        break;
-      }
-      // piece 3 - is cross product indicator
-      case 2: {
-        np++;
-        if (*start_piece == 'Y')
-          ff = aeXPRODUCT;
-        break;
+        // piece 3 - is cross product indicator
+        case 2: {
+          np++;
+          if (*piece == 'Y')
+            ff = aeXPRODUCT;
+          break;
+        }
+
+        // piece 4 - is number of affentries
+        case 3: {
+          np++;
+          numents = atoi(piece);
+          if ((numents <= 0) || ((std::numeric_limits<size_t>::max() /
+                                  sizeof(struct affentry)) < static_cast<size_t>(numents))) {
+            char* err = pHMgr->encode_flag(aflag);
+            if (err) {
+              HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
+                               af->getlinenum());
+              free(err);
+            }
+            return 1;
+          }
+          affentries.resize(numents);
+          affentries[0].opts = ff;
+          if (utf8)
+            affentries[0].opts += aeUTF8;
+          if (pHMgr->is_aliasf())
+            affentries[0].opts += aeALIASF;
+          if (pHMgr->is_aliasm())
+            affentries[0].opts += aeALIASM;
+          affentries[0].aflag = aflag;
+        }
+
+        default:
+          break;
       }
-
-      // piece 4 - is number of affentries
-      case 3: {
-        np++;
-        numents = atoi(std::string(start_piece, iter).c_str());
-        if ((numents <= 0) || ((std::numeric_limits<size_t>::max() /
-                                sizeof(AffEntry)) < static_cast<size_t>(numents))) {
-          char* err = pHMgr->encode_flag(aflag);
-          if (err) {
-            HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
-                             af->getlinenum());
-            free(err);
-          }
-          return false;
-        }
-
-        char opts = ff;
-        if (utf8)
-          opts += aeUTF8;
-        if (pHMgr->is_aliasf())
-          opts += aeALIASF;
-        if (pHMgr->is_aliasm())
-          opts += aeALIASM;
-        affentries.initialize(numents, opts, aflag);
-      }
-
-      default:
-        break;
+      i++;
     }
-    ++i;
-    start_piece = mystrsep(line, iter);
+    piece = mystrsep(&tp, 0);
   }
   // check to make sure we parsed enough pieces
   if (np != 4) {
     char* err = pHMgr->encode_flag(aflag);
     if (err) {
       HUNSPELL_WARNING(stderr, "error: line %d: missing data\n",
                        af->getlinenum());
       free(err);
     }
-    return false;
+    return 1;
   }
 
   // now parse numents affentries for this affix
-  AffEntry* entry = affentries.first_entry();
-  for (int ent = 0; ent < numents; ++ent) {
-    std::string nl;
-    if (!af->getline(nl))
-      return false;
+  std::vector<affentry>::iterator start = affentries.begin();
+  std::vector<affentry>::iterator end = affentries.end();
+  for (std::vector<affentry>::iterator entry = start; entry != end; ++entry) {
+    if ((nl = af->getline()) == NULL)
+      return 1;
     mychomp(nl);
-
-    iter = nl.begin();
+    tp = nl;
     i = 0;
     np = 0;
 
     // split line into pieces
-    start_piece = mystrsep(nl, iter);
-    while (start_piece != nl.end()) {
-      switch (i) {
-        // piece 1 - is type
-        case 0: {
-          np++;
-          if (ent != 0)
-            entry = affentries.add_entry((char)(aeXPRODUCT + aeUTF8 + aeALIASF + aeALIASM));
-          break;
-        }
-
-        // piece 2 - is affix char
-        case 1: {
-          np++;
-          std::string chunk(start_piece, iter);
-          if (pHMgr->decode_flag(chunk.c_str()) != aflag) {
-            char* err = pHMgr->encode_flag(aflag);
-            if (err) {
-              HUNSPELL_WARNING(stderr,
-                               "error: line %d: affix %s is corrupt\n",
-                               af->getlinenum(), err);
-              free(err);
-            }
-            return false;
-          }
-
-          if (ent != 0) {
-            AffEntry* start_entry = affentries.first_entry();
-            entry->aflag = start_entry->aflag;
+    piece = mystrsep(&tp, 0);
+    while (piece) {
+      if (*piece != '\0') {
+        switch (i) {
+          // piece 1 - is type
+          case 0: {
+            np++;
+            if (entry != start)
+              entry->opts = start->opts &
+                            (char)(aeXPRODUCT + aeUTF8 + aeALIASF + aeALIASM);
+            break;
           }
-          break;
-        }
-
-        // piece 3 - is string to strip or 0 for null
-        case 2: {
-          np++;
-          entry->strip = std::string(start_piece, iter);
-          if (complexprefixes) {
-            if (utf8)
-              reverseword_utf(entry->strip);
-            else
-              reverseword(entry->strip);
-          }
-          if (entry->strip.compare("0") == 0) {
-            entry->strip.clear();
+
+          // piece 2 - is affix char
+          case 1: {
+            np++;
+            if (pHMgr->decode_flag(piece) != aflag) {
+              char* err = pHMgr->encode_flag(aflag);
+              if (err) {
+                HUNSPELL_WARNING(stderr,
+                                 "error: line %d: affix %s is corrupt\n",
+                                 af->getlinenum(), err);
+                free(err);
+              }
+              return 1;
+            }
+
+            if (entry != start)
+              entry->aflag = start->aflag;
+            break;
           }
-          break;
-        }
-
-        // piece 4 - is affix string or 0 for null
-        case 3: {
-          entry->morphcode = NULL;
-          entry->contclass = NULL;
-          entry->contclasslen = 0;
-          np++;
-          std::string::const_iterator dash = std::find(start_piece, iter, '/');
-          if (dash != iter) {
-            entry->appnd = std::string(start_piece, dash);
-            std::string dash_str(dash + 1, iter);
-
-            if (!ignorechars.empty()) {
-              if (utf8) {
-                remove_ignored_chars_utf(entry->appnd, ignorechars_utf16);
-              } else {
-                remove_ignored_chars(entry->appnd, ignorechars);
-              }
-            }
-
+
+          // piece 3 - is string to strip or 0 for null
+          case 2: {
+            np++;
+            entry->strip = piece;
             if (complexprefixes) {
               if (utf8)
-                reverseword_utf(entry->appnd);
+                reverseword_utf(entry->strip);
               else
-                reverseword(entry->appnd);
+                reverseword(entry->strip);
+            }
+            if (entry->strip.compare("0") == 0) {
+              entry->strip.clear();
             }
-
-            if (pHMgr->is_aliasf()) {
-              int index = atoi(dash_str.c_str());
-              entry->contclasslen = (unsigned short)pHMgr->get_aliasf(
-                  index, &(entry->contclass), af);
-              if (!entry->contclasslen)
-                HUNSPELL_WARNING(stderr,
-                                 "error: bad affix flag alias: \"%s\"\n",
-                                 dash_str.c_str());
+            break;
+          }
+
+          // piece 4 - is affix string or 0 for null
+          case 3: {
+            char* dash;
+            entry->morphcode = NULL;
+            entry->contclass = NULL;
+            entry->contclasslen = 0;
+            np++;
+            dash = strchr(piece, '/');
+            if (dash) {
+              *dash = '\0';
+
+              entry->appnd = piece;
+
+              if (ignorechars) {
+                if (utf8) {
+                  remove_ignored_chars_utf(entry->appnd, ignorechars_utf16);
+                } else {
+                  remove_ignored_chars(entry->appnd, ignorechars);
+                }
+              }
+
+              if (complexprefixes) {
+                if (utf8)
+                  reverseword_utf(entry->appnd);
+                else
+                  reverseword(entry->appnd);
+              }
+
+              if (pHMgr->is_aliasf()) {
+                int index = atoi(dash + 1);
+                entry->contclasslen = (unsigned short)pHMgr->get_aliasf(
+                    index, &(entry->contclass), af);
+                if (!entry->contclasslen)
+                  HUNSPELL_WARNING(stderr,
+                                   "error: bad affix flag alias: \"%s\"\n",
+                                   dash + 1);
+              } else {
+                entry->contclasslen = (unsigned short)pHMgr->decode_flags(
+                    &(entry->contclass), dash + 1, af);
+                std::sort(entry->contclass, entry->contclass + entry->contclasslen);
+              }
+              *dash = '/';
+
+              havecontclass = 1;
+              for (unsigned short _i = 0; _i < entry->contclasslen; _i++) {
+                contclasses[(entry->contclass)[_i]] = 1;
+              }
             } else {
-              entry->contclasslen = (unsigned short)pHMgr->decode_flags(
-                  &(entry->contclass), dash_str.c_str(), af);
-              std::sort(entry->contclass, entry->contclass + entry->contclasslen);
-            }
-
-            havecontclass = 1;
-            for (unsigned short _i = 0; _i < entry->contclasslen; _i++) {
-              contclasses[(entry->contclass)[_i]] = 1;
-            }
-          } else {
-            entry->appnd = std::string(start_piece, iter);
-
-            if (!ignorechars.empty()) {
-              if (utf8) {
-                remove_ignored_chars_utf(entry->appnd, ignorechars_utf16);
-              } else {
-                remove_ignored_chars(entry->appnd, ignorechars);
+              entry->appnd = piece;
+
+              if (ignorechars) {
+                if (utf8) {
+                  remove_ignored_chars_utf(entry->appnd, ignorechars_utf16);
+                } else {
+                  remove_ignored_chars(entry->appnd, ignorechars);
+                }
+              }
+
+              if (complexprefixes) {
+                if (utf8)
+                  reverseword_utf(entry->appnd);
+                else
+                  reverseword(entry->appnd);
               }
             }
 
-            if (complexprefixes) {
-              if (utf8)
-                reverseword_utf(entry->appnd);
-              else
-                reverseword(entry->appnd);
+            if (entry->appnd.compare("0") == 0) {
+              entry->appnd.clear();
             }
-          }
-
-          if (entry->appnd.compare("0") == 0) {
-            entry->appnd.clear();
+            break;
           }
-          break;
-        }
-
-        // piece 5 - is the conditions descriptions
-        case 4: {
-          std::string chunk(start_piece, iter);
-          np++;
-          if (complexprefixes) {
-            if (utf8)
-              reverseword_utf(chunk);
-            else
-              reverseword(chunk);
-            reverse_condition(chunk);
-          }
-          if (!entry->strip.empty() && chunk != "." &&
-              redundant_condition(at, entry->strip.c_str(), entry->strip.size(), chunk.c_str(),
-                                  af->getlinenum()))
-            chunk = ".";
-          if (at == 'S') {
-            reverseword(chunk);
-            reverse_condition(chunk);
-          }
-          if (encodeit(*entry, chunk.c_str()))
-            return false;
-          break;
-        }
-
-        case 5: {
-          std::string chunk(start_piece, iter);
-          np++;
-          if (pHMgr->is_aliasm()) {
-            int index = atoi(chunk.c_str());
-            entry->morphcode = pHMgr->get_aliasm(index);
-          } else {
-            if (complexprefixes) {  // XXX - fix me for morph. gen.
+
+          // piece 5 - is the conditions descriptions
+          case 4: {
+            std::string chunk(piece);
+            np++;
+            if (complexprefixes) {
               if (utf8)
                 reverseword_utf(chunk);
               else
                 reverseword(chunk);
+              reverse_condition(chunk);
             }
-            // add the remaining of the line
-            std::string::const_iterator end = nl.end();
-            if (iter != end) {
-              chunk.append(iter, end);
+            if (!entry->strip.empty() && chunk != "." &&
+                redundant_condition(at, entry->strip.c_str(), entry->strip.size(), chunk.c_str(),
+                                    af->getlinenum()))
+              chunk = ".";
+            if (at == 'S') {
+              reverseword(chunk);
+              reverse_condition(chunk);
             }
-            entry->morphcode = mystrdup(chunk.c_str());
-            if (!entry->morphcode)
-              return false;
+            if (encodeit(*entry, chunk.c_str()))
+              return 1;
+            break;
           }
-          break;
+
+          case 5: {
+            std::string chunk(piece);
+            np++;
+            if (pHMgr->is_aliasm()) {
+              int index = atoi(chunk.c_str());
+              entry->morphcode = pHMgr->get_aliasm(index);
+            } else {
+              if (complexprefixes) {  // XXX - fix me for morph. gen.
+                if (utf8)
+                  reverseword_utf(chunk);
+                else
+                  reverseword(chunk);
+              }
+              // add the remaining of the line
+              if (*tp) {
+                *(tp - 1) = ' ';
+                chunk.push_back(' ');
+                chunk.append(tp);
+              }
+              entry->morphcode = mystrdup(chunk.c_str());
+              if (!entry->morphcode)
+                return 1;
+            }
+            break;
+          }
+          default:
+            break;
         }
-        default:
-          break;
+        i++;
       }
-      i++;
-      start_piece = mystrsep(nl, iter);
+      piece = mystrsep(&tp, 0);
     }
     // check to make sure we parsed enough pieces
     if (np < 4) {
       char* err = pHMgr->encode_flag(aflag);
       if (err) {
         HUNSPELL_WARNING(stderr, "error: line %d: affix %s is corrupt\n",
                          af->getlinenum(), err);
         free(err);
       }
-      return false;
+      return 1;
     }
 
 #ifdef DEBUG
     // detect unnecessary fields, excepting comments
     if (basefieldnum) {
       int fieldnum =
           !(entry->morphcode) ? 5 : ((*(entry->morphcode) == '#') ? 5 : 6);
       if (fieldnum != basefieldnum)
@@ -4757,30 +4977,26 @@ bool AffixMgr::parse_affix(const std::st
       basefieldnum =
           !(entry->morphcode) ? 5 : ((*(entry->morphcode) == '#') ? 5 : 6);
     }
 #endif
   }
 
   // now create SfxEntry or PfxEntry objects and use links to
   // build an ordered (sorted by affix string) list
-  std::vector<AffEntry*>::iterator start = affentries.begin();
-  std::vector<AffEntry*>::iterator end = affentries.end();
-  for (std::vector<AffEntry*>::iterator affentry = start; affentry != end; ++affentry) {
+  for (std::vector<affentry>::iterator entry = start; entry != end; ++entry) {
     if (at == 'P') {
-      build_pfxtree(static_cast<PfxEntry*>(*affentry));
+      PfxEntry* pfxptr = new PfxEntry(this, &(*entry));
+      build_pfxtree(pfxptr);
     } else {
-      build_sfxtree(static_cast<SfxEntry*>(*affentry));
+      SfxEntry* sfxptr = new SfxEntry(this, &(*entry));
+      build_sfxtree(sfxptr);
     }
   }
-
-  //contents belong to AffixMgr now
-  affentries.release();
-
-  return true;
+  return 0;
 }
 
 int AffixMgr::redundant_condition(char ft,
                                   const char* strip,
                                   int stripl,
                                   const char* cond,
                                   int linenum) {
   int condl = strlen(cond);
@@ -4867,33 +5083,35 @@ int AffixMgr::redundant_condition(char f
       }
       if (j < 0)
         return 1;
     }
   }
   return 0;
 }
 
-std::vector<std::string> AffixMgr::get_suffix_words(short unsigned* suff,
+int AffixMgr::get_suffix_words(short unsigned* suff,
                                int len,
-                               const char* root_word) {
-  std::vector<std::string> slst;
+                               const char* root_word,
+                               char** slst) {
+  int suff_words_cnt = 0;
   short unsigned* start_ptr = suff;
   for (int j = 0; j < SETSIZE; j++) {
     SfxEntry* ptr = sStart[j];
     while (ptr) {
       suff = start_ptr;
       for (int i = 0; i < len; i++) {
         if ((*suff) == ptr->getFlag()) {
           std::string nw(root_word);
           nw.append(ptr->getAffix());
-          hentry* ht = ptr->checkword(nw.c_str(), nw.size(), 0, NULL, 0, 0, 0);
+          hentry* ht = ptr->checkword(nw.c_str(), nw.size(), 0, NULL, NULL, 0,
+                                      NULL, 0, 0, 0);
           if (ht) {
-            slst.push_back(nw);
+            slst[suff_words_cnt++] = mystrdup(nw.c_str());
           }
         }
         suff++;
       }
       ptr = ptr->getNext();
     }
   }
-  return slst;
+  return suff_words_cnt;
 }
--- a/extensions/spellcheck/hunspell/src/affixmgr.hxx
+++ b/extensions/spellcheck/hunspell/src/affixmgr.hxx
@@ -66,47 +66,49 @@
  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
-#ifndef AFFIXMGR_HXX_
-#define AFFIXMGR_HXX_
+#ifndef _AFFIXMGR_HXX_
+#define _AFFIXMGR_HXX_
+
+#include "hunvisapi.h"
 
 #include <stdio.h>
 
 #include <string>
-#include <vector>
 
 #include "atypes.hxx"
 #include "baseaffix.hxx"
 #include "hashmgr.hxx"
 #include "phonet.hxx"
 #include "replist.hxx"
 
 // check flag duplication
 #define dupSFX (1 << 0)
 #define dupPFX (1 << 1)
 
 class PfxEntry;
 class SfxEntry;
 
-class AffixMgr {
+class LIBHUNSPELL_DLL_EXPORTED AffixMgr {
   PfxEntry* pStart[SETSIZE];
   SfxEntry* sStart[SETSIZE];
   PfxEntry* pFlag[SETSIZE];
   SfxEntry* sFlag[SETSIZE];
-  const std::vector<HashMgr*>& alldic;
-  const HashMgr* pHMgr;
-  std::string keystring;
-  std::string trystring;
-  std::string encoding;
+  HashMgr* pHMgr;
+  HashMgr** alldic;
+  int* maxdic;
+  char* keystring;
+  char* trystring;
+  char* encoding;
   struct cs_info* csconv;
   int utf8;
   int complexprefixes;
   FLAG compoundflag;
   FLAG compoundbegin;
   FLAG compoundmiddle;
   FLAG compoundend;
   FLAG compoundroot;
@@ -118,55 +120,56 @@ class AffixMgr {
   int checkcompoundcase;
   int checkcompoundtriple;
   int simplifiedtriple;
   FLAG forbiddenword;
   FLAG nosuggest;
   FLAG nongramsuggest;
   FLAG needaffix;
   int cpdmin;
-  bool parsedrep;
-  std::vector<replentry> reptable;
+  int numrep;
+  replentry* reptable;
   RepList* iconvtable;
   RepList* oconvtable;
-  bool parsedmaptable;
-  std::vector<mapentry> maptable;
-  bool parsedbreaktable;
-  std::vector<std::string> breaktable;
-  bool parsedcheckcpd;
-  std::vector<patentry> checkcpdtable;
+  int nummap;
+  mapentry* maptable;
+  int numbreak;
+  char** breaktable;
+  int numcheckcpd;
+  patentry* checkcpdtable;
   int simplifiedcpd;
-  bool parseddefcpd;
-  std::vector<flagentry> defcpdtable;
+  int numdefcpd;
+  flagentry* defcpdtable;
   phonetable* phone;
   int maxngramsugs;
   int maxcpdsugs;
   int maxdiff;
   int onlymaxdiff;
   int nosplitsugs;
   int sugswithdots;
   int cpdwordmax;
   int cpdmaxsyllable;
-  std::string cpdvowels; // vowels (for calculating of Hungarian compounding limit,
-  std::vector<w_char> cpdvowels_utf16; //vowels for UTF-8 encoding
-  std::string cpdsyllablenum; // syllable count incrementing flag
+  char* cpdvowels;
+  w_char* cpdvowels_utf16;
+  int cpdvowels_utf16_len;
+  char* cpdsyllablenum;
   const char* pfxappnd;  // BUG: not stateless
   const char* sfxappnd;  // BUG: not stateless
   int sfxextra;          // BUG: not stateless
   FLAG sfxflag;          // BUG: not stateless
   char* derived;         // BUG: not stateless
   SfxEntry* sfx;         // BUG: not stateless
   PfxEntry* pfx;         // BUG: not stateless
   int checknum;
-  std::string wordchars; // letters + spec. word characters
+  char* wordchars;
   std::vector<w_char> wordchars_utf16;
-  std::string ignorechars; // letters + spec. word characters
+  char* ignorechars;
   std::vector<w_char> ignorechars_utf16;
-  std::string version;   // affix and dictionary file version string
-  std::string lang;	 // language
+  char* version;
+  char* lang;
   int langnum;
   FLAG lemma_present;
   FLAG circumfix;
   FLAG onlyincompound;
   FLAG keepcase;
   FLAG forceucase;
   FLAG warn;
   int forbidwarn;
@@ -174,17 +177,17 @@ class AffixMgr {
   int checksharps;
   int fullstrip;
 
   int havecontclass;           // boolean variable
   char contclasses[CONTSIZE];  // flags of possible continuing classes (twofold
                                // affix)
 
  public:
-  AffixMgr(const char* affpath, const std::vector<HashMgr*>& ptr, const char* key = NULL);
+  AffixMgr(const char* affpath, HashMgr** ptr, int* md, const char* key = NULL);
   ~AffixMgr();
   struct hentry* affix_check(const char* word,
                              int len,
                              const unsigned short needflag = (unsigned short)0,
                              char in_compound = IN_CPD_NOT);
   struct hentry* prefix_check(const char* word,
                               int len,
                               char in_compound,
@@ -194,58 +197,61 @@ class AffixMgr {
                                      int len,
                                      char in_compound,
                                      const FLAG needflag = FLAG_NULL);
   inline int isRevSubset(const char* s1, const char* end_of_s2, int len);
   struct hentry* suffix_check(const char* word,
                               int len,
                               int sfxopts,
                               PfxEntry* ppfx,
+                              char** wlst,
+                              int maxSug,
+                              int* ns,
                               const FLAG cclass = FLAG_NULL,
                               const FLAG needflag = FLAG_NULL,
                               char in_compound = IN_CPD_NOT);
   struct hentry* suffix_check_twosfx(const char* word,
                                      int len,
                                      int sfxopts,
                                      PfxEntry* ppfx,
                                      const FLAG needflag = FLAG_NULL);
 
-  std::string affix_check_morph(const char* word,
-                                int len,
-                                const FLAG needflag = FLAG_NULL,
-                                char in_compound = IN_CPD_NOT);
-  std::string prefix_check_morph(const char* word,
-                                 int len,
-                                 char in_compound,
-                                 const FLAG needflag = FLAG_NULL);
-  std::string suffix_check_morph(const char* word,
-                                 int len,
-                                 int sfxopts,
-                                 PfxEntry* ppfx,
-                                 const FLAG cclass = FLAG_NULL,
-                                 const FLAG needflag = FLAG_NULL,
-                                 char in_compound = IN_CPD_NOT);
+  char* affix_check_morph(const char* word,
+                          int len,
+                          const FLAG needflag = FLAG_NULL,
+                          char in_compound = IN_CPD_NOT);
+  char* prefix_check_morph(const char* word,
+                           int len,
+                           char in_compound,
+                           const FLAG needflag = FLAG_NULL);
+  char* suffix_check_morph(const char* word,