Bug 1566288 - Port libGraphite usage in libThebes to use the RLBox API. r=froydnj draft
authorshravanrn@gmail.com <shravanrn@gmail.com>
Tue, 10 Dec 2019 03:03:09 +0000
changeset 2526020 8225409e8513929ce0a2ebccc70835d1ed6a55fc
parent 2482890 b5c5ba07d3dbd0d07b66fa42a103f4df2c27d3a2
child 2526021 6df2c873462ec9da843a099bceebaa80cf9b218a
push id462912
push userreviewbot
push dateTue, 10 Dec 2019 03:03:49 +0000
treeherdertry@2d62b86e7290 [default view] [failures only]
reviewersfroydnj
bugs1566288
milestone72.0a1
Bug 1566288 - Port libGraphite usage in libThebes to use the RLBox API. r=froydnj Summary: Differential Revision: https://phabricator.services.mozilla.com/D39593 Test Plan: Reviewers: froydnj Subscribers: Bug #: 1566288 Differential Diff: PHID-DIFF-t3woex7pbibftaiy36g2
build/clang-plugin/Utils.h
config/external/moz.build
config/external/rlbox/moz.build
gfx/graphite2/geckoextra/include/GraphiteStructsForRLBox.h
gfx/graphite2/src/moz.build
gfx/thebes/ThebesRLBox.h
gfx/thebes/ThebesRLBoxTypes.h
gfx/thebes/gfxFontEntry.cpp
gfx/thebes/gfxFontEntry.h
gfx/thebes/gfxGraphiteShaper.cpp
gfx/thebes/gfxGraphiteShaper.h
gfx/thebes/moz.build
--- a/build/clang-plugin/Utils.h
+++ b/build/clang-plugin/Utils.h
@@ -167,29 +167,31 @@ inline bool isInIgnoredNamespaceForImpli
          Name == "google" ||            // protobuf
          Name == "google_breakpad" ||   // breakpad
          Name == "soundtouch" ||        // libsoundtouch
          Name == "stagefright" ||       // libstagefright
          Name == "MacFileUtilities" ||  // MacFileUtilities
          Name == "dwarf2reader" ||      // dwarf2reader
          Name == "arm_ex_to_module" ||  // arm_ex_to_module
          Name == "testing" ||           // gtest
-         Name == "Json";                // jsoncpp
+         Name == "Json" ||              // jsoncpp
+         Name == "rlbox";               // rlbox
 }
 
 inline bool isInIgnoredNamespaceForImplicitConversion(const Decl *Declaration) {
   std::string Name = getDeclarationNamespace(Declaration);
   if (Name == "") {
     return false;
   }
 
   return Name == "std" ||             // standard C++ lib
          Name == "__gnu_cxx" ||       // gnu C++ lib
          Name == "google_breakpad" || // breakpad
-         Name == "testing";           // gtest
+         Name == "testing" ||         // gtest
+         Name == "rlbox";             // rlbox
 }
 
 inline bool isIgnoredPathForImplicitConversion(const Decl *Declaration) {
   Declaration = Declaration->getCanonicalDecl();
   SourceLocation Loc = Declaration->getLocation();
   const SourceManager &SM = Declaration->getASTContext().getSourceManager();
   SmallString<1024> FileName = getFilename(SM, Loc);
   llvm::sys::fs::make_absolute(FileName);
--- a/config/external/moz.build
+++ b/config/external/moz.build
@@ -3,16 +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/.
 
 external_dirs = []
 
 DIRS += [
     'lgpllibs',
+    'rlbox',
     'sqlite',
 ]
 if not CONFIG['MOZ_SYSTEM_JPEG']:
     external_dirs += ['media/libjpeg']
 
 DIRS += [
     '/third_party/prio',
     '/third_party/msgpack',
new file mode 100644
--- /dev/null
+++ b/config/external/rlbox/moz.build
@@ -0,0 +1,22 @@
+# -*- 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/.
+
+EXPORTS.mozilla.rlbox += [
+    '/third_party/rlbox/include/rlbox.hpp',
+    '/third_party/rlbox/include/rlbox_conversion.hpp',
+    '/third_party/rlbox/include/rlbox_helpers.hpp',
+    '/third_party/rlbox/include/rlbox_noop_sandbox.hpp',
+    '/third_party/rlbox/include/rlbox_policy_types.hpp',
+    '/third_party/rlbox/include/rlbox_range.hpp',
+    '/third_party/rlbox/include/rlbox_sandbox.hpp',
+    '/third_party/rlbox/include/rlbox_stdlib.hpp',
+    '/third_party/rlbox/include/rlbox_stdlib_polyfill.hpp',
+    '/third_party/rlbox/include/rlbox_struct_support.hpp',
+    '/third_party/rlbox/include/rlbox_type_traits.hpp',
+    '/third_party/rlbox/include/rlbox_types.hpp',
+    '/third_party/rlbox/include/rlbox_unwrap.hpp',
+    '/third_party/rlbox/include/rlbox_wrapper_traits.hpp',
+]
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/geckoextra/include/GraphiteStructsForRLBox.h
@@ -0,0 +1,58 @@
+// -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// vim: set ts=2 et sw=2 tw=80:
+// This Source Code is subject to the terms of the Mozilla Public License
+// version 2.0 (the "License"). You can obtain a copy of the License at
+// http://mozilla.org/MPL/2.0/.
+
+#ifndef GraphiteStructsForRLBox_h__
+#define GraphiteStructsForRLBox_h__
+
+#if defined(__clang__)
+#  pragma clang diagnostic push
+#  pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
+#elif defined(__GNUC__) || defined(__GNUG__)
+// Can't turn off the variadic macro warning emitted from -pedantic
+#  pragma GCC system_header
+#elif defined(_MSC_VER)
+// Doesn't seem to emit the warning
+#else
+// Don't know the compiler... just let it go through
+#endif
+
+#define sandbox_fields_reflection_graphite_class_gr_font_ops(f, g, ...)                       \
+  f(size_t, size, FIELD_NORMAL, ##__VA_ARGS__) g()                                            \
+  f(float (*)(const void*, unsigned short), glyph_advance_x, FIELD_NORMAL, ##__VA_ARGS__) g() \
+  f(float (*)(const void*, unsigned short), glyph_advance_y, FIELD_NORMAL, ##__VA_ARGS__) g()
+
+#define sandbox_fields_reflection_graphite_class_gr_face_ops(f, g, ...)                              \
+  f(size_t, size, FIELD_NORMAL, ##__VA_ARGS__) g()                                                   \
+  f(const void* (*)(const void*, unsigned int, size_t*), get_table, FIELD_NORMAL, ##__VA_ARGS__) g() \
+  f(void (*)(const void*, const void*), release_table, FIELD_NORMAL, ##__VA_ARGS__) g()
+
+#define sandbox_fields_reflection_graphite_class_gr_glyph_to_char_cluster(f, g, ...) \
+  f(unsigned int, baseChar, FIELD_NORMAL, ##__VA_ARGS__) g()                               \
+  f(unsigned int, baseGlyph, FIELD_NORMAL, ##__VA_ARGS__) g()                              \
+  f(unsigned int, nChars, FIELD_NORMAL, ##__VA_ARGS__) g()                                 \
+  f(unsigned int, nGlyphs, FIELD_NORMAL, ##__VA_ARGS__) g()
+
+#define sandbox_fields_reflection_graphite_class_gr_glyph_to_char_association(f, g, ...) \
+  f(gr_glyph_to_char_cluster*, clusters, FIELD_NORMAL, ##__VA_ARGS__) g()           \
+  f(unsigned short*, gids, FIELD_NORMAL, ##__VA_ARGS__) g()                               \
+  f(float*, xLocs, FIELD_NORMAL, ##__VA_ARGS__) g()                                       \
+  f(float*, yLocs, FIELD_NORMAL, ##__VA_ARGS__) g()                                       \
+  f(unsigned int, cIndex, FIELD_NORMAL, ##__VA_ARGS__) g()
+
+#define sandbox_fields_reflection_graphite_allClasses(f, ...)                  \
+  f(gr_font_ops, graphite, ##__VA_ARGS__)                                      \
+  f(gr_face_ops, graphite, ##__VA_ARGS__)                                      \
+  f(gr_glyph_to_char_cluster, graphite, ##__VA_ARGS__)                         \
+  f(gr_glyph_to_char_association, graphite, ##__VA_ARGS__)
+
+#if defined(__clang__)
+#  pragma clang diagnostic pop
+#elif defined(__GNUC__) || defined(__GNUG__)
+#elif defined(_MSC_VER)
+#else
+#endif
+
+#endif
\ No newline at end of file
--- a/gfx/graphite2/src/moz.build
+++ b/gfx/graphite2/src/moz.build
@@ -2,16 +2,17 @@
 # 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/.
 
 # This should contain all of the _PUBLIC_HEADERS from files.mk
 EXPORTS.graphite2 += [
     '../geckoextra/include/GraphiteExtra.h',
+    '../geckoextra/include/GraphiteStructsForRLBox.h',
     '../include/graphite2/Font.h',
     '../include/graphite2/Log.h',
     '../include/graphite2/Segment.h',
     '../include/graphite2/Types.h',
 ]
 
 if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
     UNIFIED_SOURCES += [
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/ThebesRLBox.h
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 THEBES_RLBOX
+#define THEBES_RLBOX
+
+#include "ThebesRLBoxTypes.h"
+
+// RLBox uses c++17's shared_locks by default, even for the noop_sandbox
+// However c++17 shared_lock is not supported on macOS 10.9 to 10.11
+// Thus we use Firefox's shared lock implementation
+// This can be removed if macOS 10.9 to 10.11 support is dropped
+#include "mozilla/RWLock.h"
+namespace rlbox {
+struct rlbox_shared_lock {
+  mozilla::RWLock rwlock;
+  rlbox_shared_lock() : rwlock("rlbox") {}
+};
+}  // namespace rlbox
+#define RLBOX_USE_CUSTOM_SHARED_LOCK
+#define RLBOX_SHARED_LOCK(name) rlbox::rlbox_shared_lock name
+#define RLBOX_ACQUIRE_SHARED_GUARD(name, ...) \
+  mozilla::AutoReadLock name((__VA_ARGS__).rwlock)
+#define RLBOX_ACQUIRE_UNIQUE_GUARD(name, ...) \
+  mozilla::AutoWriteLock name((__VA_ARGS__).rwlock)
+
+#define RLBOX_SINGLE_THREADED_INVOCATIONS
+
+#define RLBOX_USE_STATIC_CALLS() rlbox_noop_sandbox_lookup_symbol
+
+#include "mozilla/rlbox/rlbox.hpp"
+#include "mozilla/rlbox/rlbox_noop_sandbox.hpp"
+
+// Struct info needed for rlbox_load_structs_from_library
+#include "graphite2/Font.h"
+#include "graphite2/GraphiteExtra.h"
+#include "graphite2/Segment.h"
+
+#include "graphite2/GraphiteStructsForRLBox.h"
+rlbox_load_structs_from_library(graphite);
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/ThebesRLBoxTypes.h
@@ -0,0 +1,22 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 THEBES_RLBOX_TYPES
+#define THEBES_RLBOX_TYPES
+
+#include "mozilla/rlbox/rlbox_types.hpp"
+
+using rlbox_gr_sandbox_type = rlbox::rlbox_noop_sandbox;
+using rlbox_sandbox_gr = rlbox::rlbox_sandbox<rlbox_gr_sandbox_type>;
+template <typename T>
+using sandbox_callback_gr = rlbox::sandbox_callback<T, rlbox_gr_sandbox_type>;
+template <typename T>
+using tainted_gr = rlbox::tainted<T, rlbox_gr_sandbox_type>;
+template <typename T>
+using tainted_opaque_gr = rlbox::tainted_opaque<T, rlbox_gr_sandbox_type>;
+template <typename T>
+using tainted_volatile_gr = rlbox::tainted_volatile<T, rlbox_gr_sandbox_type>;
+
+#endif
--- a/gfx/thebes/gfxFontEntry.cpp
+++ b/gfx/thebes/gfxFontEntry.cpp
@@ -25,26 +25,29 @@
 #include "nsMathUtils.h"
 #include "nsBidiUtils.h"
 #include "nsStyleConsts.h"
 #include "mozilla/AppUnits.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/ScopeExit.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPrefs_layout.h"
 #include "mozilla/Telemetry.h"
 #include "gfxSVGGlyphs.h"
 #include "gfx2DGlue.h"
 
 #include "harfbuzz/hb.h"
 #include "harfbuzz/hb-ot.h"
 #include "graphite2/Font.h"
 
+#include "ThebesRLBox.h"
+
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::unicode;
 using mozilla::services::GetObserverService;
 
 void gfxCharacterMap::NotifyReleased() {
@@ -590,64 +593,151 @@ hb_face_t* gfxFontEntry::GetHBFace() {
   if (!mHBFace) {
     mHBFace =
         hb_face_create_for_tables(HBGetTable, this, HBFaceDeletedCallback);
     return mHBFace;
   }
   return hb_face_reference(mHBFace);
 }
 
-/*static*/ const void* gfxFontEntry::GrGetTable(const void* aAppFaceHandle,
-                                                unsigned int aName,
-                                                size_t* aLen) {
-  gfxFontEntry* fontEntry =
-      static_cast<gfxFontEntry*>(const_cast<void*>(aAppFaceHandle));
-  hb_blob_t* blob = fontEntry->GetFontTable(aName);
-  if (blob) {
-    unsigned int blobLength;
-    const void* tableData = hb_blob_get_data(blob, &blobLength);
-    fontEntry->mGrTableMap->Put(tableData, blob);
-    *aLen = blobLength;
-    return tableData;
+struct gfxFontEntry::GrSandboxData {
+  rlbox_sandbox_gr sandbox;
+  sandbox_callback_gr<const void* (*)(const void*, unsigned int, size_t*)>
+      grGetTableCallback;
+  sandbox_callback_gr<void (*)(const void*, const void*)>
+      grReleaseTableCallback;
+  // Text Shapers register a callback to get glyph advances
+  sandbox_callback_gr<float (*)(const void*, uint16_t)>
+      grGetGlyphAdvanceCallback;
+
+  GrSandboxData() {
+    sandbox.create_sandbox();
+    grGetTableCallback = sandbox.register_callback(GrGetTable);
+    grReleaseTableCallback = sandbox.register_callback(GrReleaseTable);
+    grGetGlyphAdvanceCallback =
+        sandbox.register_callback(gfxGraphiteShaper::GrGetAdvance);
+  }
+
+  ~GrSandboxData() {
+    grGetTableCallback.unregister();
+    grReleaseTableCallback.unregister();
+    grGetGlyphAdvanceCallback.unregister();
+    sandbox.destroy_sandbox();
   }
-  *aLen = 0;
-  return nullptr;
+};
+
+static thread_local gfxFontEntry* tl_grGetFontTableCallbackData = nullptr;
+
+/*static*/
+tainted_opaque_gr<const void*> gfxFontEntry::GrGetTable(
+    rlbox_sandbox_gr& sandbox,
+    tainted_opaque_gr<const void*> /* aAppFaceHandle */,
+    tainted_opaque_gr<unsigned int> aName, tainted_opaque_gr<size_t*> aLen) {
+  gfxFontEntry* fontEntry = tl_grGetFontTableCallbackData;
+  tainted_gr<size_t*> t_aLen = rlbox::from_opaque(aLen);
+  *t_aLen = 0;
+  tainted_gr<const void*> ret = nullptr;
+
+  if (fontEntry) {
+    hb_blob_t* blob =
+        fontEntry->GetFontTable(rlbox::from_opaque(aName).UNSAFE_unverified());
+
+    if (blob) {
+      unsigned int blobLength;
+      const void* tableData = hb_blob_get_data(blob, &blobLength);
+      // tableData is read-only data shared with the sandbox.
+      // Making a copy in sandbox memory
+      tainted_gr<void*> t_tableData = rlbox::sandbox_reinterpret_cast<void*>(
+          sandbox.malloc_in_sandbox<char>(blobLength));
+      if (t_tableData) {
+        rlbox::memcpy(sandbox, t_tableData, tableData, blobLength);
+        *t_aLen = blobLength;
+        ret = rlbox::sandbox_const_cast<const void*>(t_tableData);
+      }
+      hb_blob_destroy(blob);
+    }
+  }
+
+  return ret.to_opaque();
 }
 
 /*static*/
-void gfxFontEntry::GrReleaseTable(const void* aAppFaceHandle,
-                                  const void* aTableBuffer) {
-  gfxFontEntry* fontEntry =
-      static_cast<gfxFontEntry*>(const_cast<void*>(aAppFaceHandle));
-  void* value;
-  if (fontEntry->mGrTableMap->Remove(aTableBuffer, &value)) {
-    hb_blob_destroy(static_cast<hb_blob_t*>(value));
-  }
+void gfxFontEntry::GrReleaseTable(
+    rlbox_sandbox_gr& sandbox,
+    tainted_opaque_gr<const void*> /* aAppFaceHandle */,
+    tainted_opaque_gr<const void*> aTableBuffer) {
+  sandbox.free_in_sandbox(rlbox::from_opaque(aTableBuffer));
+}
+
+rlbox_sandbox_gr* gfxFontEntry::GetGrSandbox() {
+  MOZ_ASSERT(mSandboxData != nullptr);
+  return &mSandboxData->sandbox;
+}
+
+sandbox_callback_gr<float (*)(const void*, uint16_t)>*
+gfxFontEntry::GetGrSandboxAdvanceCallbackHandle() {
+  MOZ_ASSERT(mSandboxData != nullptr);
+  return &mSandboxData->grGetGlyphAdvanceCallback;
 }
 
-gr_face* gfxFontEntry::GetGrFace() {
+tainted_opaque_gr<gr_face*> gfxFontEntry::GetGrFace() {
   if (!mGrFaceInitialized) {
-    gr_face_ops faceOps = {sizeof(gr_face_ops), GrGetTable, GrReleaseTable};
-    mGrTableMap = new nsDataHashtable<nsPtrHashKey<const void>, void*>;
-    mGrFace = gr_make_face_with_ops(this, &faceOps, gr_face_default);
+    // When possible, the below code will use WASM as a sandboxing mechanism.
+    // At this time the wasm sandbox does not support threads.
+    // If Thebes is updated to make callst to the sandbox on multiple threaads,
+    // we need to make sure the underlying sandbox supports threading.
+    MOZ_ASSERT(NS_IsMainThread());
+
+    mSandboxData = new GrSandboxData();
+
+    auto p_faceOps = mSandboxData->sandbox.malloc_in_sandbox<gr_face_ops>();
+    if (!p_faceOps) {
+      MOZ_CRASH("Graphite sandbox memory allocation failed");
+    }
+    auto cleanup = MakeScopeExit(
+        [&] { mSandboxData->sandbox.free_in_sandbox(p_faceOps); });
+    p_faceOps->size = sizeof(*p_faceOps);
+    p_faceOps->get_table = mSandboxData->grGetTableCallback;
+    p_faceOps->release_table = mSandboxData->grReleaseTableCallback;
+
+    tl_grGetFontTableCallbackData = this;
+    auto face = sandbox_invoke(
+        mSandboxData->sandbox, gr_make_face_with_ops,
+        // For security, we do not pass the callback data to this arg, and use
+        // a TLS var instead. However, gr_make_face_with_ops expects this to
+        // be a non null ptr. Therefore,  we should pass some dummy non null
+        // pointer which will be passed to callbacks, but never used. Let's just
+        // pass p_faceOps again, as this is a non-null tainted pointer.
+        p_faceOps /* appFaceHandle */, p_faceOps, gr_face_default);
+    tl_grGetFontTableCallbackData = nullptr;
+    mGrFace = face.to_opaque();
     mGrFaceInitialized = true;
   }
   ++mGrFaceRefCnt;
   return mGrFace;
 }
 
-void gfxFontEntry::ReleaseGrFace(gr_face* aFace) {
-  MOZ_ASSERT(aFace == mGrFace);  // sanity-check
+void gfxFontEntry::ReleaseGrFace(tainted_opaque_gr<gr_face*> aFace) {
+  MOZ_ASSERT(rlbox::from_opaque(aFace).UNSAFE_unverified() ==
+             rlbox::from_opaque(mGrFace).UNSAFE_unverified());  // sanity-check
   MOZ_ASSERT(mGrFaceRefCnt > 0);
   if (--mGrFaceRefCnt == 0) {
-    gr_face_destroy(mGrFace);
-    mGrFace = nullptr;
+    auto t_mGrFace = rlbox::from_opaque(mGrFace);
+
+    tl_grGetFontTableCallbackData = this;
+    sandbox_invoke(mSandboxData->sandbox, gr_face_destroy, t_mGrFace);
+    tl_grGetFontTableCallbackData = nullptr;
+
+    t_mGrFace = nullptr;
+    mGrFace = t_mGrFace.to_opaque();
+
+    delete mSandboxData;
+    mSandboxData = nullptr;
+
     mGrFaceInitialized = false;
-    delete mGrTableMap;
-    mGrTableMap = nullptr;
   }
 }
 
 void gfxFontEntry::DisconnectSVG() {
   if (mSVGInitialized && mSVGGlyphs) {
     mSVGGlyphs = nullptr;
     mSVGInitialized = false;
   }
@@ -659,19 +749,22 @@ bool gfxFontEntry::HasFontTable(uint32_t
 }
 
 void gfxFontEntry::CheckForGraphiteTables() {
   mHasGraphiteTables = HasFontTable(TRUETYPE_TAG('S', 'i', 'l', 'f'));
 }
 
 bool gfxFontEntry::HasGraphiteSpaceContextuals() {
   if (!mGraphiteSpaceContextualsInitialized) {
-    gr_face* face = GetGrFace();
-    if (face) {
-      const gr_faceinfo* faceInfo = gr_face_info(face, 0);
+    auto face = GetGrFace();
+    auto t_face = rlbox::from_opaque(face);
+    if (t_face) {
+      const gr_faceinfo* faceInfo =
+          sandbox_invoke(mSandboxData->sandbox, gr_face_info, t_face, 0)
+              .UNSAFE_unverified();
       mHasGraphiteSpaceContextuals =
           faceInfo->space_contextuals != gr_faceinfo::gr_space_none;
     }
     ReleaseGrFace(face);  // always balance GetGrFace, even if face is null
     mGraphiteSpaceContextualsInitialized = true;
   }
   return mHasGraphiteSpaceContextuals;
 }
@@ -830,18 +923,21 @@ bool gfxFontEntry::SupportsGraphiteFeatu
 
   // graphite feature check uses the last script slot
   uint32_t scriptFeature = SCRIPT_FEATURE(FEATURE_SCRIPT_MASK, aFeatureTag);
   bool result;
   if (mSupportedFeatures->Get(scriptFeature, &result)) {
     return result;
   }
 
-  gr_face* face = GetGrFace();
-  result = face ? gr_face_find_fref(face, aFeatureTag) != nullptr : false;
+  auto face = GetGrFace();
+  auto t_face = rlbox::from_opaque(face);
+  result = t_face ? sandbox_invoke(mSandboxData->sandbox, gr_face_find_fref,
+                                   t_face, aFeatureTag) != nullptr
+                  : false;
   ReleaseGrFace(face);
 
   mSupportedFeatures->Put(scriptFeature, result);
 
   return result;
 }
 
 void gfxFontEntry::GetFeatureInfo(nsTArray<gfxFontFeatureInfo>& aFeatureInfo) {
--- a/gfx/thebes/gfxFontEntry.h
+++ b/gfx/thebes/gfxFontEntry.h
@@ -19,16 +19,17 @@
 #include "MainThreadUtils.h"
 #include "nsUnicodeScriptCodes.h"
 #include "nsDataHashtable.h"
 #include "harfbuzz/hb.h"
 #include "mozilla/FontPropertyTypes.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/WeakPtr.h"
+#include "ThebesRLBoxTypes.h"
 #include <math.h>
 
 typedef struct gr_face gr_face;
 typedef struct FT_MM_Var_ FT_MM_Var;
 
 #ifdef DEBUG
 #  include <stdio.h>
 #endif
@@ -332,20 +333,31 @@ class gfxFontEntry {
   // object in completely different ways.
 
   // Get HarfBuzz face corresponding to this font file.
   // Caller must release with hb_face_destroy() when finished with it,
   // and the font entry will be notified via ForgetHBFace.
   hb_face_t* GetHBFace();
   void ForgetHBFace();
 
+  // Get the sandbox instance that graphite is running in.
+  rlbox_sandbox_gr* GetGrSandbox();
+
+  // Register and get the callback handle for the glyph advance firefox callback
+  // Since the sandbox instance is shared with multiple test shapers, callback
+  // registration must be handled centrally to ensure multiple instances don't
+  // register the same callback.
+  sandbox_callback_gr<float (*)(const void*, uint16_t)>*
+  GetGrSandboxAdvanceCallbackHandle();
+
   // Get Graphite face corresponding to this font file.
   // Caller must call gfxFontEntry::ReleaseGrFace when finished with it.
-  gr_face* GetGrFace();
-  void ReleaseGrFace(gr_face* aFace);
+  // Graphite is run in a sandbox
+  tainted_opaque_gr<gr_face*> GetGrFace();
+  void ReleaseGrFace(tainted_opaque_gr<gr_face*> aFace);
 
   // Does the font have graphite contextuals that involve the space glyph
   // (and therefore we should bypass the word cache)?
   bool HasGraphiteSpaceContextuals();
 
   // Release any SVG-glyphs document this font may have loaded.
   void DisconnectSVG();
 
@@ -565,44 +577,47 @@ class gfxFontEntry {
   // it, so that a new face will be created next time it is needed.
   hb_face_t* mHBFace = nullptr;
 
   static hb_blob_t* HBGetTable(hb_face_t* face, uint32_t aTag, void* aUserData);
 
   // Callback that the hb_face will use to tell us when it is being deleted.
   static void HBFaceDeletedCallback(void* aUserData);
 
+  // All libGraphite functionality is sandboxed in an rlbox sandbox. This
+  // contains data for the sandbox instance.
+  struct GrSandboxData;
+  GrSandboxData* mSandboxData = nullptr;
+
   // gr_face is -not- refcounted, so it will be owned directly by the font
   // entry, and we'll keep a count of how many references we've handed out;
   // each shaper is responsible to call ReleaseGrFace on its entry when
   // finished with it, so that we know when it can be deleted.
-  gr_face* mGrFace = nullptr;
-
-  // hashtable to map raw table data ptr back to its owning blob, for use by
-  // graphite table-release callback
-  nsDataHashtable<nsPtrHashKey<const void>, void*>* mGrTableMap = nullptr;
+  tainted_opaque_gr<gr_face*> mGrFace;
 
   // For AAT font, a strong reference to the 'trak' table (if present).
   hb_blob_t* const kTrakTableUninitialized = (hb_blob_t*)(intptr_t(-1));
   hb_blob_t* mTrakTable = kTrakTableUninitialized;
   bool TrakTableInitialized() const {
     return mTrakTable != kTrakTableUninitialized;
   }
 
   // Cached pointers to tables within 'trak', initialized by ParseTrakTable.
   const mozilla::AutoSwap_PRInt16* mTrakValues;
   const mozilla::AutoSwap_PRInt32* mTrakSizeTable;
 
   // number of current users of this entry's mGrFace
   nsrefcnt mGrFaceRefCnt = 0;
 
-  static const void* GrGetTable(const void* aAppFaceHandle, unsigned int aName,
-                                size_t* aLen);
-  static void GrReleaseTable(const void* aAppFaceHandle,
-                             const void* aTableBuffer);
+  static tainted_opaque_gr<const void*> GrGetTable(
+      rlbox_sandbox_gr& sandbox, tainted_opaque_gr<const void*> aAppFaceHandle,
+      tainted_opaque_gr<unsigned int> aName, tainted_opaque_gr<size_t*> aLen);
+  static void GrReleaseTable(rlbox_sandbox_gr& sandbox,
+                             tainted_opaque_gr<const void*> aAppFaceHandle,
+                             tainted_opaque_gr<const void*> aTableBuffer);
 
   // For memory reporting: size of user-font data belonging to this entry.
   // We record this in the font entry because the actual data block may be
   // handed over to platform APIs, so that it would become difficult (and
   // platform-specific) to measure it directly at report-gathering time.
   uint32_t mComputedSizeOfUserFont = 0;
 
   // Font's unitsPerEm from the 'head' table, if available (will be set to
--- a/gfx/thebes/gfxGraphiteShaper.cpp
+++ b/gfx/thebes/gfxGraphiteShaper.cpp
@@ -10,16 +10,20 @@
 #include "gfxTextRun.h"
 
 #include "graphite2/Font.h"
 #include "graphite2/GraphiteExtra.h"
 #include "graphite2/Segment.h"
 
 #include "harfbuzz/hb.h"
 
+#include "mozilla/ScopeExit.h"
+
+#include "ThebesRLBox.h"
+
 #define FloatToFixed(f) (65536 * (f))
 #define FixedToFloat(f) ((f) * (1.0 / 65536.0))
 // Right shifts of negative (signed) integers are undefined, as are overflows
 // when converting unsigned to negative signed integers.
 // (If speed were an issue we could make some 2's complement assumptions.)
 #define FixedToIntRound(f) \
   ((f) > 0 ? ((32768 + (f)) >> 16) : -((32767 - (f)) >> 16))
 
@@ -27,57 +31,75 @@ using namespace mozilla;  // for AutoSwa
 
 /*
  * Creation and destruction; on deletion, release any font tables we're holding
  */
 
 gfxGraphiteShaper::gfxGraphiteShaper(gfxFont* aFont)
     : gfxFontShaper(aFont),
       mGrFace(mFont->GetFontEntry()->GetGrFace()),
-      mGrFont(nullptr),
+      mSandbox(mFont->GetFontEntry()->GetGrSandbox()),
+      mCallback(mFont->GetFontEntry()->GetGrSandboxAdvanceCallbackHandle()),
       mFallbackToSmallCaps(false) {
   mCallbackData.mFont = aFont;
 }
 
 gfxGraphiteShaper::~gfxGraphiteShaper() {
-  if (mGrFont) {
-    gr_font_destroy(mGrFont);
+  auto t_mGrFont = rlbox::from_opaque(mGrFont);
+  if (t_mGrFont) {
+    sandbox_invoke(*mSandbox, gr_font_destroy, t_mGrFont);
   }
   mFont->GetFontEntry()->ReleaseGrFace(mGrFace);
 }
 
 /*static*/
-float gfxGraphiteShaper::GrGetAdvance(const void* appFontHandle,
-                                      uint16_t glyphid) {
-  const CallbackData* cb = static_cast<const CallbackData*>(appFontHandle);
-  return FixedToFloat(cb->mFont->GetGlyphWidth(glyphid));
+thread_local gfxGraphiteShaper::CallbackData*
+    gfxGraphiteShaper::tl_GrGetAdvanceData = nullptr;
+
+/*static*/
+tainted_opaque_gr<float> gfxGraphiteShaper::GrGetAdvance(
+    rlbox_sandbox_gr& sandbox,
+    tainted_opaque_gr<const void*> /* appFontHandle */,
+    tainted_opaque_gr<uint16_t> t_glyphid) {
+  CallbackData* cb = tl_GrGetAdvanceData;
+  if (!cb) {
+    // GrGetAdvance callback called unexpectedly. Just return safe value.
+    tainted_gr<float> ret = 0;
+    return ret.to_opaque();
+  }
+  auto glyphid = rlbox::from_opaque(t_glyphid).UNSAFE_unverified();
+  tainted_gr<float> ret = FixedToFloat(cb->mFont->GetGlyphWidth(glyphid));
+  return ret.to_opaque();
 }
 
 static inline uint32_t MakeGraphiteLangTag(uint32_t aTag) {
   uint32_t grLangTag = aTag;
   // replace trailing space-padding with NULs for graphite
   uint32_t mask = 0x000000FF;
   while ((grLangTag & mask) == ' ') {
     grLangTag &= ~mask;
     mask <<= 8;
   }
   return grLangTag;
 }
 
 struct GrFontFeatures {
-  gr_face* mFace;
-  gr_feature_val* mFeatures;
+  tainted_gr<gr_face*> mFace;
+  tainted_gr<gr_feature_val*> mFeatures;
+  rlbox_sandbox_gr* mSandbox;
 };
 
 static void AddFeature(const uint32_t& aTag, uint32_t& aValue, void* aUserArg) {
   GrFontFeatures* f = static_cast<GrFontFeatures*>(aUserArg);
 
-  const gr_feature_ref* fref = gr_face_find_fref(f->mFace, aTag);
+  tainted_gr<const gr_feature_ref*> fref =
+      sandbox_invoke(*(f->mSandbox), gr_face_find_fref, f->mFace, aTag);
   if (fref) {
-    gr_fref_set_feature_value(fref, aValue, f->mFeatures);
+    sandbox_invoke(*(f->mSandbox), gr_fref_set_feature_value, fref, aValue,
+                   f->mFeatures);
   }
 }
 
 // Count the number of Unicode characters in a UTF-16 string (i.e. surrogate
 // pairs are counted as 1, although they are 2 code units).
 // (Any isolated surrogates will count 1 each, because in decoding they would
 // be replaced by individual U+FFFD REPLACEMENT CHARACTERs.)
 static inline size_t CountUnicodes(const char16_t* aText, uint32_t aLength) {
@@ -96,34 +118,49 @@ static inline size_t CountUnicodes(const
 }
 
 bool gfxGraphiteShaper::ShapeText(DrawTarget* aDrawTarget,
                                   const char16_t* aText, uint32_t aOffset,
                                   uint32_t aLength, Script aScript,
                                   bool aVertical, RoundingFlags aRounding,
                                   gfxShapedText* aShapedText) {
   const gfxFontStyle* style = mFont->GetStyle();
+  auto t_mGrFace = rlbox::from_opaque(mGrFace);
+  auto t_mGrFont = rlbox::from_opaque(mGrFont);
 
-  if (!mGrFont) {
-    if (!mGrFace) {
+  if (!t_mGrFont) {
+    if (!t_mGrFace) {
       return false;
     }
 
     if (mFont->ProvidesGlyphWidths()) {
-      gr_font_ops ops = {
-          sizeof(gr_font_ops), &GrGetAdvance,
-          nullptr  // vertical text not yet implemented
-      };
-      mGrFont = gr_make_font_with_ops(mFont->GetAdjustedSize(), &mCallbackData,
-                                      &ops, mGrFace);
+      auto p_ops = mSandbox->malloc_in_sandbox<gr_font_ops>();
+      if (!p_ops) {
+        return false;
+      }
+      auto clean_ops = MakeScopeExit([&] { mSandbox->free_in_sandbox(p_ops); });
+      p_ops->size = sizeof(*p_ops);
+      p_ops->glyph_advance_x = *mCallback;
+      p_ops->glyph_advance_y = nullptr;  // vertical text not yet implemented
+      t_mGrFont = sandbox_invoke(
+          *mSandbox, gr_make_font_with_ops, mFont->GetAdjustedSize(),
+          // For security, we do not pass the callback data to this arg, and use
+          // a TLS var instead. However, gr_make_font_with_ops expects this to
+          // be a non null ptr, and changes its behavior if it isn't. Therefore,
+          // we should pass some dummy non null pointer which will be passed to
+          // the GrGetAdvance callback, but never used. Let's just pass p_ops
+          // again, as this is a non-null tainted pointer.
+          p_ops /* mCallbackData */, p_ops, t_mGrFace);
     } else {
-      mGrFont = gr_make_font(mFont->GetAdjustedSize(), mGrFace);
+      t_mGrFont = sandbox_invoke(*mSandbox, gr_make_font,
+                                 mFont->GetAdjustedSize(), t_mGrFace);
     }
+    mGrFont = t_mGrFont.to_opaque();
 
-    if (!mGrFont) {
+    if (!t_mGrFont) {
       return false;
     }
 
     // determine whether petite-caps falls back to small-caps
     if (style->variantCaps != NS_FONT_VARIANT_CAPS_NORMAL) {
       switch (style->variantCaps) {
         case NS_FONT_VARIANT_CAPS_ALLPETITE:
         case NS_FONT_VARIANT_CAPS_PETITECAPS:
@@ -143,20 +180,21 @@ bool gfxGraphiteShaper::ShapeText(DrawTa
     grLang = MakeGraphiteLangTag(style->languageOverride);
   } else if (entry->mLanguageOverride) {
     grLang = MakeGraphiteLangTag(entry->mLanguageOverride);
   } else if (style->explicitLanguage) {
     nsAutoCString langString;
     style->language->ToUTF8String(langString);
     grLang = GetGraphiteTagForLang(langString);
   }
-  gr_feature_val* grFeatures = gr_face_featureval_for_lang(mGrFace, grLang);
+  tainted_gr<gr_feature_val*> grFeatures =
+      sandbox_invoke(*mSandbox, gr_face_featureval_for_lang, t_mGrFace, grLang);
 
   // insert any merged features into Graphite feature list
-  GrFontFeatures f = {mGrFace, grFeatures};
+  GrFontFeatures f = {t_mGrFace, grFeatures, mSandbox};
   MergeFontFeatures(style, mFont->GetFontEntry()->mFeatureSettings,
                     aShapedText->DisableLigatures(),
                     mFont->GetFontEntry()->FamilyName(), mFallbackToSmallCaps,
                     AddFeature, &f);
 
   // Graphite shaping doesn't map U+00a0 (nbsp) to space if it is missing
   // from the font, so check for that possibility. (Most fonts double-map
   // the space glyph to both 0x20 and 0xA0, so this won't often be needed;
@@ -170,74 +208,95 @@ bool gfxGraphiteShaper::ShapeText(DrawTa
       transformed.ReplaceChar(NO_BREAK_SPACE, ' ');
       aText = transformed.BeginReading();
     }
   }
 
   size_t numChars = CountUnicodes(aText, aLength);
   gr_bidirtl grBidi = gr_bidirtl(
       aShapedText->IsRightToLeft() ? (gr_rtl | gr_nobidi) : gr_nobidi);
-  gr_segment* seg = gr_make_seg(mGrFont, mGrFace, 0, grFeatures, gr_utf16,
-                                aText, numChars, grBidi);
+
+  tainted_gr<char16_t*> t_aText =
+      mSandbox->malloc_in_sandbox<char16_t>(aLength);
+  if (!t_aText) {
+    return false;
+  }
+  auto clean_txt = MakeScopeExit([&] { mSandbox->free_in_sandbox(t_aText); });
 
-  gr_featureval_destroy(grFeatures);
+  rlbox::memcpy(*mSandbox, t_aText, aText, aLength * sizeof(char16_t));
+
+  tl_GrGetAdvanceData = &mCallbackData;
+  auto clean_adv_data = MakeScopeExit([&] { tl_GrGetAdvanceData = nullptr; });
+
+  tainted_gr<gr_segment*> seg =
+      sandbox_invoke(*mSandbox, gr_make_seg, mGrFont, t_mGrFace, 0, grFeatures,
+                     gr_utf16, t_aText, numChars, grBidi);
+
+  sandbox_invoke(*mSandbox, gr_featureval_destroy, grFeatures);
 
   if (!seg) {
     return false;
   }
 
-  nsresult rv = SetGlyphsFromSegment(aShapedText, aOffset, aLength, aText, seg,
-                                     aRounding);
+  nsresult rv =
+      SetGlyphsFromSegment(aShapedText, aOffset, aLength, aText,
+                           t_aText.to_opaque(), seg.to_opaque(), aRounding);
 
-  gr_seg_destroy(seg);
+  sandbox_invoke(*mSandbox, gr_seg_destroy, seg);
 
   return NS_SUCCEEDED(rv);
 }
 
 nsresult gfxGraphiteShaper::SetGlyphsFromSegment(
     gfxShapedText* aShapedText, uint32_t aOffset, uint32_t aLength,
-    const char16_t* aText, gr_segment* aSegment, RoundingFlags aRounding) {
+    const char16_t* aText, tainted_opaque_gr<char16_t*> t_aText,
+    tainted_opaque_gr<gr_segment*> aSegment, RoundingFlags aRounding) {
   typedef gfxShapedText::CompressedGlyph CompressedGlyph;
 
   int32_t dev2appUnits = aShapedText->GetAppUnitsPerDevUnit();
   bool rtl = aShapedText->IsRightToLeft();
 
   // identify clusters; graphite may have reordered/expanded/ligated glyphs.
-  gr_glyph_to_char_association* data =
-      gr_get_glyph_to_char_association(aSegment, aLength, aText);
+  tainted_gr<gr_glyph_to_char_association*> data =
+      sandbox_invoke(*mSandbox, gr_get_glyph_to_char_association, aSegment,
+                     aLength, rlbox::from_opaque(t_aText));
 
   if (!data) {
     return NS_ERROR_FAILURE;
   }
 
-  uint32_t cIndex = data->cIndex;
-  gr_glyph_to_char_cluster* clusters = data->clusters;
-  uint16_t* gids = data->gids;
-  float* xLocs = data->xLocs;
-  float* yLocs = data->yLocs;
+  uint32_t cIndex = data->cIndex.UNSAFE_unverified();
+  gr_glyph_to_char_cluster* clusters = data->clusters.UNSAFE_unverified();
+  uint16_t* gids = data->gids.UNSAFE_unverified();
+  float* xLocs = data->xLocs.UNSAFE_unverified();
+  float* yLocs = data->yLocs.UNSAFE_unverified();
 
   CompressedGlyph* charGlyphs = aShapedText->GetCharacterGlyphs() + aOffset;
 
   bool roundX = bool(aRounding & RoundingFlags::kRoundX);
   bool roundY = bool(aRounding & RoundingFlags::kRoundY);
 
   // now put glyphs into the textrun, one cluster at a time
   for (uint32_t i = 0; i <= cIndex; ++i) {
     const gr_glyph_to_char_cluster& c = clusters[i];
 
     float adv;  // total advance of the cluster
     if (rtl) {
       if (i == 0) {
-        adv = gr_seg_advance_X(aSegment) - xLocs[c.baseGlyph];
+        adv = sandbox_invoke(*mSandbox, gr_seg_advance_X, aSegment)
+                  .UNSAFE_unverified() -
+              xLocs[c.baseGlyph];
       } else {
         adv = xLocs[clusters[i - 1].baseGlyph] - xLocs[c.baseGlyph];
       }
     } else {
       if (i == cIndex) {
-        adv = gr_seg_advance_X(aSegment) - xLocs[c.baseGlyph];
+        adv = sandbox_invoke(*mSandbox, gr_seg_advance_X, aSegment)
+                  .UNSAFE_unverified() -
+              xLocs[c.baseGlyph];
       } else {
         adv = xLocs[clusters[i + 1].baseGlyph] - xLocs[c.baseGlyph];
       }
     }
 
     // Check for default-ignorable char that didn't get filtered, combined,
     // etc by the shaping process, and skip it.
     uint32_t offs = c.baseChar;
@@ -283,17 +342,17 @@ nsresult gfxGraphiteShaper::SetGlyphsFro
     for (uint32_t j = c.baseChar + 1; j < c.baseChar + c.nChars; ++j) {
       NS_ASSERTION(j < aLength, "unexpected offset");
       CompressedGlyph& g = charGlyphs[j];
       NS_ASSERTION(!g.IsSimpleGlyph(), "overwriting a simple glyph");
       g.SetComplex(g.IsClusterStart(), false, 0);
     }
   }
 
-  gr_free_char_association(data);
+  sandbox_invoke(*mSandbox, gr_free_char_association, data);
   return NS_OK;
 }
 
 // for language tag validation - include list of tags from the IANA registry
 #include "gfxLanguageTagList.cpp"
 
 nsTHashtable<nsUint32HashKey>* gfxGraphiteShaper::sLanguageTags;
 
--- a/gfx/thebes/gfxGraphiteShaper.h
+++ b/gfx/thebes/gfxGraphiteShaper.h
@@ -5,16 +5,18 @@
 
 #ifndef GFX_GRAPHITESHAPER_H
 #define GFX_GRAPHITESHAPER_H
 
 #include "gfxFont.h"
 
 #include "mozilla/gfx/2D.h"
 
+#include "ThebesRLBoxTypes.h"
+
 struct gr_face;
 struct gr_font;
 struct gr_segment;
 
 class gfxGraphiteShaper : public gfxFontShaper {
  public:
   explicit gfxGraphiteShaper(gfxFont* aFont);
   virtual ~gfxGraphiteShaper();
@@ -24,31 +26,49 @@ class gfxGraphiteShaper : public gfxFont
                  bool aVertical, RoundingFlags aRounding,
                  gfxShapedText* aShapedText) override;
 
   static void Shutdown();
 
  protected:
   nsresult SetGlyphsFromSegment(gfxShapedText* aShapedText, uint32_t aOffset,
                                 uint32_t aLength, const char16_t* aText,
-                                gr_segment* aSegment, RoundingFlags aRounding);
+                                tainted_opaque_gr<char16_t*> t_aText,
+                                tainted_opaque_gr<gr_segment*> aSegment,
+                                RoundingFlags aRounding);
 
-  static float GrGetAdvance(const void* appFontHandle, uint16_t glyphid);
+  // Graphite is run in a rlbox sandbox. Callback GrGetAdvance must be
+  // explicitly permitted. Since the sandbox is owned in gfxFontEntry class,
+  // gfxFontEntry needs access to the protected callback.
+  friend class gfxFontEntry;
+  static tainted_opaque_gr<float> GrGetAdvance(
+      rlbox_sandbox_gr& sandbox, tainted_opaque_gr<const void*> appFontHandle,
+      tainted_opaque_gr<uint16_t> glyphid);
 
-  gr_face* mGrFace;  // owned by the font entry; shaper must call
-                     // gfxFontEntry::ReleaseGrFace when finished with it
-  gr_font* mGrFont;  // owned by the shaper itself
+  tainted_opaque_gr<gr_face*>
+      mGrFace;  // owned by the font entry; shaper must call
+                // gfxFontEntry::ReleaseGrFace when finished with it
+  tainted_opaque_gr<gr_font*> mGrFont;  // owned by the shaper itself
+
+  // All libGraphite functionality is sandboxed. This is the sandbox instance.
+  rlbox_sandbox_gr* mSandbox;
+
+  // Holds the handle to the permitted callback into Firefox for the sandboxed
+  // libGraphite
+  sandbox_callback_gr<float (*)(const void*, uint16_t)>* mCallback;
 
   struct CallbackData {
     // mFont is a pointer to the font that owns this shaper, so it will
     // remain valid throughout our lifetime
     gfxFont* MOZ_NON_OWNING_REF mFont;
   };
 
   CallbackData mCallbackData;
+  static thread_local CallbackData* tl_GrGetAdvanceData;
+
   bool mFallbackToSmallCaps;  // special fallback for the petite-caps case
 
   // Convert HTML 'lang' (BCP47) to Graphite language code
   static uint32_t GetGraphiteTagForLang(const nsCString& aLang);
   static nsTHashtable<nsUint32HashKey>* sLanguageTags;
 };
 
 #endif /* GFX_GRAPHITESHAPER_H */
--- a/gfx/thebes/moz.build
+++ b/gfx/thebes/moz.build
@@ -55,24 +55,26 @@ EXPORTS += [
     'gfxSkipChars.h',
     'gfxSVGGlyphs.h',
     'gfxTextRun.h',
     'gfxTypes.h',
     'gfxUserFontSet.h',
     'gfxUtils.h',
     'SharedFontList.h',
     'SoftwareVsyncSource.h',
+    'ThebesRLBoxTypes.h',
     'VsyncSource.h',
 ]
 
 EXPORTS.mozilla.gfx += [
     'D3D11Checks.h',
     'DeviceManagerDx.h',
     'PrintTarget.h',
     'PrintTargetThebes.h',
+    'ThebesRLBox.h',
 ]
 
 if CONFIG['MOZ_ENABLE_SKIA']:
     EXPORTS.mozilla.gfx += [
         'SkMemoryReporter.h'
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
@@ -255,16 +257,22 @@ include('/ipc/chromium/chromium-config.m
 
 FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
     '/dom/base',
     '/dom/xml',
 ]
 
+# Due to dependency on rlbox
+if CONFIG['CC_TYPE'] == 'clang-cl':
+    CXXFLAGS += ['/std:c++17']
+else:
+    CXXFLAGS += ['-std=gnu++17']
+
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gtk'):
     DEFINES['MOZ_ENABLE_FREETYPE'] = True
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     for var in ('MOZ_ENABLE_D3D10_LAYER',):
         if CONFIG[var]:
             DEFINES[var] = True