[tbb-commits] [tor-browser/tor-browser-52.5.2esr-7.5-2] Bug 23970: Printing to a file is broken with Linux content sandboxing enabled

gk at torproject.org gk at torproject.org
Fri Dec 15 10:14:14 UTC 2017


commit 2a11447e4fb8ec6d64031cc41bdcef97603343cb
Author: Richard Pospesel <richard at torproject.org>
Date:   Mon Nov 27 14:40:05 2017 -0800

    Bug 23970: Printing to a file is broken with Linux content sandboxing enabled
    
    Ported over firefox patch 2797f193a147 (Bug 1309205 Part 2)
---
 gfx/2d/2D.h                             |   7 +
 gfx/2d/Factory.cpp                      |  23 ++-
 gfx/2d/NativeFontResourceFontconfig.cpp |  65 +++++++
 gfx/2d/NativeFontResourceFontconfig.h   |  41 +++++
 gfx/2d/RecordedEvent.cpp                |  21 +--
 gfx/2d/RecordedEvent.h                  |  10 +-
 gfx/2d/ScaledFontFontconfig.cpp         | 315 ++++++++++++++++++++++++++++++++
 gfx/2d/ScaledFontFontconfig.h           |  59 +++++-
 gfx/2d/ScaledFontWin.cpp                |  17 ++
 gfx/2d/ScaledFontWin.h                  |   4 +
 gfx/2d/moz.build                        |   1 +
 11 files changed, 540 insertions(+), 23 deletions(-)

diff --git a/gfx/2d/2D.h b/gfx/2d/2D.h
index 3d5fb52ad925..0b95f37cb1c3 100644
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -1388,6 +1388,13 @@ public:
     CreateNativeFontResource(uint8_t *aData, uint32_t aSize, FontType aType);
 
   /**
+   * This creates a scaled font of the given type based on font descriptor
+   * data retrieved from ScaledFont::GetFontDescriptor.
+   */
+  static already_AddRefed<ScaledFont>
+    CreateScaledFontFromFontDescriptor(FontType aType, const uint8_t* aData, uint32_t aDataLength, Float aSize);
+
+  /**
    * This creates a scaled font with an associated cairo_scaled_font_t, and
    * must be used when using the Cairo backend. The NativeFont and
    * cairo_scaled_font_t* parameters must correspond to the same font.
diff --git a/gfx/2d/Factory.cpp b/gfx/2d/Factory.cpp
index ceebce690afb..bfe93d82c0ef 100644
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -32,6 +32,7 @@
 
 #ifdef MOZ_WIDGET_GTK
 #include "ScaledFontFontconfig.h"
+#include "NativeFontResourceFontconfig.h"
 #endif
 
 #ifdef WIN32
@@ -534,8 +535,10 @@ Factory::CreateNativeFontResource(uint8_t *aData, uint32_t aSize,
         return NativeFontResourceGDI::Create(aData, aSize,
                                              /* aNeedsCairo = */ true);
       }
-#elif XP_DARWIN
+#elif defined(XP_DARWIN)
       return NativeFontResourceMac::Create(aData, aSize);
+#elif defined(MOZ_WIDGET_GTK)
+      return NativeFontResourceFontconfig::Create(aData, aSize);
 #else
       gfxWarning() << "Unable to create cairo scaled font from truetype data";
       return nullptr;
@@ -548,6 +551,24 @@ Factory::CreateNativeFontResource(uint8_t *aData, uint32_t aSize,
 }
 
 already_AddRefed<ScaledFont>
+Factory::CreateScaledFontFromFontDescriptor(FontType aType, const uint8_t* aData, uint32_t aDataLength, Float aSize)
+{
+  switch (aType) {
+#ifdef WIN32
+  case FontType::GDI:
+    return ScaledFontWin::CreateFromFontDescriptor(aData, aDataLength, aSize);
+#endif
+#ifdef MOZ_WIDGET_GTK
+  case FontType::FONTCONFIG:
+    return ScaledFontFontconfig::CreateFromFontDescriptor(aData, aDataLength, aSize);
+#endif
+  default:
+    gfxWarning() << "Invalid type specified for ScaledFont font descriptor";
+    return nullptr;
+  }
+}
+
+already_AddRefed<ScaledFont>
 Factory::CreateScaledFontWithCairo(const NativeFont& aNativeFont, Float aSize, cairo_scaled_font_t* aScaledFont)
 {
 #ifdef USE_CAIRO
diff --git a/gfx/2d/NativeFontResourceFontconfig.cpp b/gfx/2d/NativeFontResourceFontconfig.cpp
new file mode 100644
index 000000000000..a205f98fae08
--- /dev/null
+++ b/gfx/2d/NativeFontResourceFontconfig.cpp
@@ -0,0 +1,65 @@
+/* -*- 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 "NativeFontResourceFontconfig.h"
+#include "ScaledFontFontconfig.h"
+#include "Logging.h"
+
+namespace mozilla {
+namespace gfx {
+
+NativeFontResourceFontconfig::NativeFontResourceFontconfig(UniquePtr<uint8_t[]>&& aFontData, FT_Face aFace)
+  : mFontData(Move(aFontData)),
+    mFace(aFace)
+{
+}
+
+NativeFontResourceFontconfig::~NativeFontResourceFontconfig()
+{
+  if (mFace) {
+    FT_Done_Face(mFace);
+    mFace = nullptr;
+  }
+}
+
+already_AddRefed<NativeFontResourceFontconfig>
+NativeFontResourceFontconfig::Create(uint8_t *aFontData, uint32_t aDataLength)
+{
+  if (!aFontData || !aDataLength) {
+    return nullptr;
+  }
+  UniquePtr<uint8_t[]> fontData(new uint8_t[aDataLength]);
+  memcpy(fontData.get(), aFontData, aDataLength);
+
+  FT_Face face;
+  if (FT_New_Memory_Face(Factory::GetFTLibrary(), fontData.get(), aDataLength, 0, &face) != FT_Err_Ok) {
+    return nullptr;
+  }
+  if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != FT_Err_Ok) {
+    FT_Done_Face(face);
+    return nullptr;
+  }
+
+  RefPtr<NativeFontResourceFontconfig> resource =
+    new NativeFontResourceFontconfig(Move(fontData), face);
+  return resource.forget();
+}
+
+already_AddRefed<ScaledFont>
+NativeFontResourceFontconfig::CreateScaledFont(uint32_t aIndex, Float aGlyphSize,
+                                               const uint8_t* aInstanceData, uint32_t aInstanceDataLength)
+{
+  if (aInstanceDataLength < sizeof(ScaledFontFontconfig::InstanceData)) {
+    gfxWarning() << "Fontconfig scaled font instance data is truncated.";
+    return nullptr;
+  }
+  return ScaledFontFontconfig::CreateFromInstanceData(
+           *reinterpret_cast<const ScaledFontFontconfig::InstanceData*>(aInstanceData),
+           mFace, nullptr, 0, aGlyphSize);
+}
+
+} // gfx
+} // mozilla
diff --git a/gfx/2d/NativeFontResourceFontconfig.h b/gfx/2d/NativeFontResourceFontconfig.h
new file mode 100644
index 000000000000..e2c386198896
--- /dev/null
+++ b/gfx/2d/NativeFontResourceFontconfig.h
@@ -0,0 +1,41 @@
+/* -*- 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/. */
+
+#ifndef mozilla_gfx_NativeFontResourceFontconfig_h
+#define mozilla_gfx_NativeFontResourceFontconfig_h
+
+#include "2D.h"
+
+#include <cairo-ft.h>
+
+namespace mozilla {
+namespace gfx {
+
+class NativeFontResourceFontconfig final : public NativeFontResource
+{
+public:
+  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(NativeFontResourceFontconfig)
+
+  static already_AddRefed<NativeFontResourceFontconfig>
+    Create(uint8_t *aFontData, uint32_t aDataLength);
+
+  already_AddRefed<ScaledFont>
+    CreateScaledFont(uint32_t aIndex, Float aGlyphSize,
+                     const uint8_t* aInstanceData, uint32_t aInstanceDataLength) final;
+
+  ~NativeFontResourceFontconfig();
+
+private:
+  NativeFontResourceFontconfig(UniquePtr<uint8_t[]>&& aFontData, FT_Face aFace);
+
+  UniquePtr<uint8_t[]> mFontData;
+  FT_Face mFace;
+};
+
+} // gfx
+} // mozilla
+
+#endif // mozilla_gfx_NativeFontResourceFontconfig_h
diff --git a/gfx/2d/RecordedEvent.cpp b/gfx/2d/RecordedEvent.cpp
index 3bfc5c8f6333..684ce180db1e 100644
--- a/gfx/2d/RecordedEvent.cpp
+++ b/gfx/2d/RecordedEvent.cpp
@@ -1595,18 +1595,13 @@ RecordedFontDescriptor::~RecordedFontDescriptor()
 bool
 RecordedFontDescriptor::PlayEvent(Translator *aTranslator) const
 {
-  MOZ_ASSERT(mType == FontType::GDI);
-
-  NativeFont nativeFont;
-  nativeFont.mType = (NativeFontType)mType;
-  nativeFont.mFont = (void*)&mData[0];
-
   RefPtr<ScaledFont> font =
-    Factory::CreateScaledFontForNativeFont(nativeFont, mFontSize);
-
-#ifdef USE_CAIRO_SCALED_FONT
-  static_cast<ScaledFontBase*>(font.get())->PopulateCairoScaledFont();
-#endif
+    Factory::CreateScaledFontFromFontDescriptor(mType, mData.data(), mData.size(), mFontSize);
+  if (!font) {
+    gfxDevCrash(LogReason::InvalidFont) <<
+      "Failed creating ScaledFont of type " << int(mType) << " from font descriptor";
+    return false;
+  }
 
   aTranslator->AddScaledFont(mRefPtr, font);
   return true;
@@ -1620,7 +1615,7 @@ RecordedFontDescriptor::RecordToStream(std::ostream &aStream) const
   WriteElement(aStream, mFontSize);
   WriteElement(aStream, mRefPtr);
   WriteElement(aStream, (size_t)mData.size());
-  aStream.write((char*)&mData[0], mData.size());
+  aStream.write((char*)mData.data(), mData.size());
 }
 
 void
@@ -1646,7 +1641,7 @@ RecordedFontDescriptor::RecordedFontDescriptor(istream &aStream)
   size_t size;
   ReadElement(aStream, size);
   mData.resize(size);
-  aStream.read((char*)&mData[0], size);
+  aStream.read((char*)mData.data(), size);
 }
 
 bool
diff --git a/gfx/2d/RecordedEvent.h b/gfx/2d/RecordedEvent.h
index bf660ba243c4..dcf4d9e36e02 100644
--- a/gfx/2d/RecordedEvent.h
+++ b/gfx/2d/RecordedEvent.h
@@ -1047,7 +1047,7 @@ private:
   uint8_t *mData;
   RecordedFontDetails mFontDetails;
 
-  bool mGetFontFileDataSucceeded = false;
+  bool mGetFontFileDataSucceeded;
 
   MOZ_IMPLICIT RecordedFontData(std::istream &aStream);
 };
@@ -1055,7 +1055,7 @@ private:
 class RecordedFontDescriptor : public RecordedEvent {
 public:
 
-  static void FontDescCb(const uint8_t *aData, uint32_t aSize,
+  static void FontDescCb(const uint8_t* aData, uint32_t aSize,
                          Float aFontSize, void* aBaton)
   {
     auto recordedFontDesc = static_cast<RecordedFontDescriptor*>(aBaton);
@@ -1108,9 +1108,11 @@ public:
 
   RecordedScaledFontCreation(ScaledFont* aScaledFont,
                              RecordedFontDetails aFontDetails)
-    : RecordedEvent(SCALEDFONTCREATION), mRefPtr(aScaledFont)
+    : RecordedEvent(SCALEDFONTCREATION)
+    , mRefPtr(aScaledFont)
     , mFontDataKey(aFontDetails.fontDataKey)
-    , mGlyphSize(aFontDetails.glyphSize) , mIndex(aFontDetails.index)
+    , mGlyphSize(aFontDetails.glyphSize)
+    , mIndex(aFontDetails.index)
   {
     aScaledFont->GetFontInstanceData(FontInstanceDataProc, this);
   }
diff --git a/gfx/2d/ScaledFontFontconfig.cpp b/gfx/2d/ScaledFontFontconfig.cpp
index d4751f86dac1..0695eebbeaa7 100644
--- a/gfx/2d/ScaledFontFontconfig.cpp
+++ b/gfx/2d/ScaledFontFontconfig.cpp
@@ -10,6 +10,10 @@
 #include "skia/include/ports/SkTypeface_cairo.h"
 #endif
 
+#include FT_TRUETYPE_TABLES_H
+
+#include <fontconfig/fcfreetype.h>
+
 namespace mozilla {
 namespace gfx {
 
@@ -43,5 +47,316 @@ SkTypeface* ScaledFontFontconfig::GetSkTypeface()
 }
 #endif
 
+bool
+ScaledFontFontconfig::GetFontFileData(FontFileDataOutput aDataCallback, void* aBaton)
+{
+  bool success = false;
+  // Lock the Cairo scaled font to force it to resolve the Fontconfig pattern to an FT_Face.
+  if (FT_Face face = cairo_ft_scaled_font_lock_face(GetCairoScaledFont())) {
+    FT_ULong length = 0;
+    // Request the SFNT file. This may not always succeed for all font types.
+    if (FT_Load_Sfnt_Table(face, 0, 0, nullptr, &length) == FT_Err_Ok) {
+      uint8_t* fontData = new uint8_t[length];
+      if (FT_Load_Sfnt_Table(face, 0, 0, fontData, &length) == FT_Err_Ok) {
+        aDataCallback(fontData, length, 0, mSize, aBaton);
+        success = true;
+      }
+      delete[] fontData;
+    }
+    cairo_ft_scaled_font_unlock_face(GetCairoScaledFont());
+  }
+  return success;
+}
+
+ScaledFontFontconfig::InstanceData::InstanceData(cairo_scaled_font_t* aScaledFont, FcPattern* aPattern)
+  : mFlags(0)
+  , mHintStyle(FC_HINT_NONE)
+  , mSubpixelOrder(FC_RGBA_UNKNOWN)
+  , mLcdFilter(FC_LCD_LEGACY)
+{
+  // Record relevant Fontconfig properties into instance data.
+  FcBool autohint;
+  if (FcPatternGetBool(aPattern, FC_AUTOHINT, 0, &autohint) == FcResultMatch && autohint) {
+    mFlags |= AUTOHINT;
+  }
+  FcBool bitmap;
+  if (FcPatternGetBool(aPattern, FC_EMBEDDED_BITMAP, 0, &bitmap) == FcResultMatch && bitmap) {
+    mFlags |= EMBEDDED_BITMAP;
+  }
+  FcBool embolden;
+  if (FcPatternGetBool(aPattern, FC_EMBOLDEN, 0, &embolden) == FcResultMatch && embolden) {
+    mFlags |= EMBOLDEN;
+  }
+  FcBool vertical;
+  if (FcPatternGetBool(aPattern, FC_VERTICAL_LAYOUT, 0, &vertical) == FcResultMatch && vertical) {
+    mFlags |= VERTICAL_LAYOUT;
+  }
+
+  FcBool antialias;
+  if (FcPatternGetBool(aPattern, FC_ANTIALIAS, 0, &antialias) != FcResultMatch || antialias) {
+    mFlags |= ANTIALIAS;
+
+    // Only record subpixel order and lcd filtering if antialiasing is enabled.
+    int rgba;
+    if (FcPatternGetInteger(aPattern, FC_RGBA, 0, &rgba) == FcResultMatch) {
+      mSubpixelOrder = rgba;
+    }
+    int filter;
+    if (FcPatternGetInteger(aPattern, FC_LCD_FILTER, 0, &filter) == FcResultMatch) {
+      mLcdFilter = filter;
+    }
+  }
+
+  cairo_font_options_t* fontOptions = cairo_font_options_create();
+  cairo_scaled_font_get_font_options(aScaledFont, fontOptions);
+  // For printer fonts, Cairo hint metrics and hinting will be disabled.
+  // For other fonts, allow hint metrics and hinting.
+  if (cairo_font_options_get_hint_metrics(fontOptions) != CAIRO_HINT_METRICS_OFF) {
+    mFlags |= HINT_METRICS;
+
+    FcBool hinting;
+    if (FcPatternGetBool(aPattern, FC_HINTING, 0, &hinting) != FcResultMatch || hinting) {
+      int hintstyle;
+      if (FcPatternGetInteger(aPattern, FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch) {
+        hintstyle = FC_HINT_FULL;
+      }
+      mHintStyle = hintstyle;
+    }
+  }
+  cairo_font_options_destroy(fontOptions);
+
+  // Some fonts supply an adjusted size or otherwise use the font matrix for italicization.
+  // Record the scale and the skew to accomodate both of these cases.
+  cairo_matrix_t fontMatrix;
+  cairo_scaled_font_get_font_matrix(aScaledFont, &fontMatrix);
+  mScale = Float(fontMatrix.xx);
+  mSkew = Float(fontMatrix.xy);
+}
+
+void
+ScaledFontFontconfig::InstanceData::SetupPattern(FcPattern* aPattern) const
+{
+  if (mFlags & AUTOHINT) {
+    FcPatternAddBool(aPattern, FC_AUTOHINT, FcTrue);
+  }
+  if (mFlags & EMBEDDED_BITMAP) {
+    FcPatternAddBool(aPattern, FC_EMBEDDED_BITMAP, FcTrue);
+  }
+  if (mFlags & EMBOLDEN) {
+    FcPatternAddBool(aPattern, FC_EMBOLDEN, FcTrue);
+  }
+  if (mFlags & VERTICAL_LAYOUT) {
+    FcPatternAddBool(aPattern, FC_VERTICAL_LAYOUT, FcTrue);
+  }
+
+  if (mFlags & ANTIALIAS) {
+    FcPatternAddBool(aPattern, FC_ANTIALIAS, FcTrue);
+    if (mSubpixelOrder != FC_RGBA_UNKNOWN) {
+      FcPatternAddInteger(aPattern, FC_RGBA, mSubpixelOrder);
+    }
+    if (mLcdFilter != FC_LCD_LEGACY) {
+      FcPatternAddInteger(aPattern, FC_LCD_FILTER, mLcdFilter);
+    }
+  } else {
+    FcPatternAddBool(aPattern, FC_ANTIALIAS, FcFalse);
+  }
+
+  if (mHintStyle) {
+    FcPatternAddBool(aPattern, FC_HINTING, FcTrue);
+    FcPatternAddInteger(aPattern, FC_HINT_STYLE, mHintStyle);
+  } else {
+    FcPatternAddBool(aPattern, FC_HINTING, FcFalse);
+  }
+}
+
+void
+ScaledFontFontconfig::InstanceData::SetupFontOptions(cairo_font_options_t* aFontOptions) const
+{
+  // Try to build a sane initial set of Cairo font options based on the Fontconfig
+  // pattern.
+  if (mFlags & HINT_METRICS) {
+    // For regular (non-printer) fonts, enable hint metrics as well as hinting
+    // and (possibly subpixel) antialiasing.
+    cairo_font_options_set_hint_metrics(aFontOptions, CAIRO_HINT_METRICS_ON);
+
+    cairo_hint_style_t hinting;
+    switch (mHintStyle) {
+    case FC_HINT_NONE:
+      hinting = CAIRO_HINT_STYLE_NONE;
+      break;
+    case FC_HINT_SLIGHT:
+      hinting = CAIRO_HINT_STYLE_SLIGHT;
+      break;
+    case FC_HINT_MEDIUM:
+    default:
+      hinting = CAIRO_HINT_STYLE_MEDIUM;
+      break;
+    case FC_HINT_FULL:
+      hinting = CAIRO_HINT_STYLE_FULL;
+      break;
+    }
+    cairo_font_options_set_hint_style(aFontOptions, hinting);
+
+    if (mFlags & ANTIALIAS) {
+      cairo_subpixel_order_t subpixel = CAIRO_SUBPIXEL_ORDER_DEFAULT;
+      switch (mSubpixelOrder) {
+      case FC_RGBA_RGB:
+        subpixel = CAIRO_SUBPIXEL_ORDER_RGB;
+        break;
+      case FC_RGBA_BGR:
+        subpixel = CAIRO_SUBPIXEL_ORDER_BGR;
+        break;
+      case FC_RGBA_VRGB:
+        subpixel = CAIRO_SUBPIXEL_ORDER_VRGB;
+        break;
+      case FC_RGBA_VBGR:
+        subpixel = CAIRO_SUBPIXEL_ORDER_VBGR;
+        break;
+      default:
+        break;
+      }
+      if (subpixel != CAIRO_SUBPIXEL_ORDER_DEFAULT) {
+        cairo_font_options_set_antialias(aFontOptions, CAIRO_ANTIALIAS_SUBPIXEL);
+        cairo_font_options_set_subpixel_order(aFontOptions, subpixel);
+      } else {
+        cairo_font_options_set_antialias(aFontOptions, CAIRO_ANTIALIAS_GRAY);
+      }
+    } else {
+      cairo_font_options_set_antialias(aFontOptions, CAIRO_ANTIALIAS_NONE);
+    }
+  } else {
+    // For printer fonts, disable hint metrics and hinting. Don't allow subpixel
+    // antialiasing.
+    cairo_font_options_set_hint_metrics(aFontOptions, CAIRO_HINT_METRICS_OFF);
+    cairo_font_options_set_hint_style(aFontOptions, CAIRO_HINT_STYLE_NONE);
+    cairo_font_options_set_antialias(aFontOptions,
+      mFlags & ANTIALIAS ? CAIRO_ANTIALIAS_GRAY : CAIRO_ANTIALIAS_NONE);
+  }
+}
+
+void
+ScaledFontFontconfig::InstanceData::SetupFontMatrix(cairo_matrix_t* aFontMatrix) const
+{
+  // Build a font matrix that will reproduce a possibly adjusted size
+  // and any italics/skew. This is just the concatenation of a simple
+  // scale matrix with a matrix that skews on the X axis.
+  cairo_matrix_init(aFontMatrix, mScale, 0, mSkew, mScale, 0, 0);
+}
+
+bool
+ScaledFontFontconfig::GetFontInstanceData(FontInstanceDataOutput aCb, void* aBaton)
+{
+  InstanceData instance(GetCairoScaledFont(), mPattern);
+
+  aCb(reinterpret_cast<uint8_t*>(&instance), sizeof(instance), aBaton);
+  return true;
+}
+
+bool
+ScaledFontFontconfig::GetFontDescriptor(FontDescriptorOutput aCb, void* aBaton)
+{
+  // Check if the Fontconfig pattern uses a font file and index to specify which
+  // font to load. If so, record these as a font descriptor along with any instance
+  // data required to rebuild a scaled font from it.
+  FcChar8* pathname = nullptr;
+  if (FcPatternGetString(mPattern, FC_FILE, 0, &pathname) != FcResultMatch) {
+    return false;
+  }
+  int index = 0;
+  FcPatternGetInteger(mPattern, FC_INDEX, 0, &index);
+  if (index < 0) {
+    return false;
+  }
+
+  size_t pathLength = strlen(reinterpret_cast<char*>(pathname)) + 1;
+  size_t dataLength = sizeof(FontDescriptor) + pathLength;
+  uint8_t* data = new uint8_t[dataLength];
+  FontDescriptor* desc = reinterpret_cast<FontDescriptor*>(data);
+  desc->mPathLength = pathLength;
+  desc->mIndex = index;
+  desc->mInstanceData = InstanceData(GetCairoScaledFont(), mPattern);
+  memcpy(data + sizeof(FontDescriptor), pathname, pathLength);
+
+  aCb(data, dataLength, mSize, aBaton);
+  return true;
+}
+
+already_AddRefed<ScaledFont>
+ScaledFontFontconfig::CreateFromInstanceData(const InstanceData& aInstanceData,
+                                             FT_Face aFace, const char* aPathname, uint32_t aIndex,
+                                             Float aSize)
+
+{
+  FcPattern* pattern = FcPatternCreate();
+  if (!pattern) {
+    gfxWarning() << "Failing initializing Fontconfig pattern for scaled font";
+    return nullptr;
+  }
+  if (aFace) {
+    FcPatternAddFTFace(pattern, FC_FT_FACE, aFace);
+  } else {
+    FcPatternAddString(pattern, FC_FILE, reinterpret_cast<const FcChar8*>(aPathname));
+    FcPatternAddInteger(pattern, FC_INDEX, aIndex);
+  }
+  FcPatternAddDouble(pattern, FC_PIXEL_SIZE, aSize);
+  aInstanceData.SetupPattern(pattern);
+
+  cairo_font_face_t* font = cairo_ft_font_face_create_for_pattern(pattern);
+  if (cairo_font_face_status(font) != CAIRO_STATUS_SUCCESS) {
+    gfxWarning() << "Failed creating Cairo font face for Fontconfig pattern";
+    FcPatternDestroy(pattern);
+    return nullptr;
+  }
+
+  cairo_matrix_t sizeMatrix;
+  aInstanceData.SetupFontMatrix(&sizeMatrix);
+
+  cairo_matrix_t identityMatrix;
+  cairo_matrix_init_identity(&identityMatrix);
+
+  cairo_font_options_t *fontOptions = cairo_font_options_create();
+  aInstanceData.SetupFontOptions(fontOptions);
+
+  cairo_scaled_font_t* cairoScaledFont =
+    cairo_scaled_font_create(font, &sizeMatrix, &identityMatrix, fontOptions);
+
+  cairo_font_options_destroy(fontOptions);
+  cairo_font_face_destroy(font);
+
+  if (cairo_scaled_font_status(cairoScaledFont) != CAIRO_STATUS_SUCCESS) {
+    gfxWarning() << "Failed creating Cairo scaled font for font face";
+    FcPatternDestroy(pattern);
+    return nullptr;
+  }
+
+  RefPtr<ScaledFontFontconfig> scaledFont =
+    new ScaledFontFontconfig(cairoScaledFont, pattern, aSize);
+
+  FcPatternDestroy(pattern);
+
+  return scaledFont.forget();
+}
+
+already_AddRefed<ScaledFont>
+ScaledFontFontconfig::CreateFromFontDescriptor(const uint8_t* aData, uint32_t aDataLength, Float aSize)
+{
+  if (aDataLength < sizeof(FontDescriptor)) {
+    gfxWarning() << "Fontconfig font descriptor is truncated.";
+    return nullptr;
+  }
+  const FontDescriptor* desc = reinterpret_cast<const FontDescriptor*>(aData);
+  if (desc->mPathLength < 1 ||
+      desc->mPathLength > aDataLength - sizeof(FontDescriptor)) {
+    gfxWarning() << "Pathname in Fontconfig font descriptor has invalid size.";
+    return nullptr;
+  }
+  const char* pathname = reinterpret_cast<const char*>(aData + sizeof(FontDescriptor));
+  if (pathname[desc->mPathLength - 1] != '\0') {
+    gfxWarning() << "Pathname in Fontconfig font descriptor is not terminated.";
+    return nullptr;
+  }
+  return CreateFromInstanceData(desc->mInstanceData, nullptr, pathname, desc->mIndex, aSize);
+}
+
 } // namespace gfx
 } // namespace mozilla
diff --git a/gfx/2d/ScaledFontFontconfig.h b/gfx/2d/ScaledFontFontconfig.h
index 4d4e8217dc1f..b24928d9db05 100644
--- a/gfx/2d/ScaledFontFontconfig.h
+++ b/gfx/2d/ScaledFontFontconfig.h
@@ -8,26 +8,75 @@
 
 #include "ScaledFontBase.h"
 
-#include <fontconfig/fontconfig.h>
-#include <cairo.h>
+#include <cairo-ft.h>
 
 namespace mozilla {
 namespace gfx {
 
+class NativeFontResourceFontconfig;
+
 class ScaledFontFontconfig : public ScaledFontBase
 {
 public:
-  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontFontconfig)
+  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontFontconfig, override)
   ScaledFontFontconfig(cairo_scaled_font_t* aScaledFont, FcPattern* aPattern, Float aSize);
   ~ScaledFontFontconfig();
 
-  virtual FontType GetType() const { return FontType::FONTCONFIG; }
+  FontType GetType() const override { return FontType::FONTCONFIG; }
 
 #ifdef USE_SKIA
-  virtual SkTypeface* GetSkTypeface();
+  SkTypeface* GetSkTypeface() override;
 #endif
 
+  bool GetFontFileData(FontFileDataOutput aDataCallback, void* aBaton) override;
+
+  bool GetFontInstanceData(FontInstanceDataOutput aCb, void* aBaton) override;
+
+  bool GetFontDescriptor(FontDescriptorOutput aCb, void* aBaton) override;
+
+  static already_AddRefed<ScaledFont>
+    CreateFromFontDescriptor(const uint8_t* aData, uint32_t aDataLength, Float aSize);
+
 private:
+  friend class NativeFontResourceFontconfig;
+
+  struct InstanceData
+  {
+    enum {
+      ANTIALIAS       = 1 << 0,
+      AUTOHINT        = 1 << 1,
+      EMBEDDED_BITMAP = 1 << 2,
+      EMBOLDEN        = 1 << 3,
+      VERTICAL_LAYOUT = 1 << 4,
+      HINT_METRICS    = 1 << 5
+    };
+
+    InstanceData(cairo_scaled_font_t* aScaledFont, FcPattern* aPattern);
+
+    void SetupPattern(FcPattern* aPattern) const;
+    void SetupFontOptions(cairo_font_options_t* aFontOptions) const;
+    void SetupFontMatrix(cairo_matrix_t* aFontMatrix) const;
+
+    uint8_t mFlags;
+    uint8_t mHintStyle;
+    uint8_t mSubpixelOrder;
+    uint8_t mLcdFilter;
+    Float mScale;
+    Float mSkew;
+  };
+
+  struct FontDescriptor
+  {
+    uint32_t mPathLength;
+    uint32_t mIndex;
+    InstanceData mInstanceData;
+  };
+
+  static already_AddRefed<ScaledFont>
+    CreateFromInstanceData(const InstanceData& aInstanceData,
+                           FT_Face aFace, const char* aPathname, uint32_t aIndex,
+                           Float aSize);
+
   FcPattern* mPattern;
 };
 
diff --git a/gfx/2d/ScaledFontWin.cpp b/gfx/2d/ScaledFontWin.cpp
index 2ebae21e5c04..b80bbea872e2 100644
--- a/gfx/2d/ScaledFontWin.cpp
+++ b/gfx/2d/ScaledFontWin.cpp
@@ -72,6 +72,23 @@ ScaledFontWin::GetFontDescriptor(FontDescriptorOutput aCb, void* aBaton)
   return true;
 }
 
+already_AddRefed<ScaledFont>
+ScaledFontWin::CreateFromFontDescriptor(const uint8_t* aData, uint32_t aDataLength, Float aSize)
+{
+  NativeFont nativeFont;
+  nativeFont.mType = NativeFontType::GDI_FONT_FACE;
+  nativeFont.mFont = (void*)aData;
+
+  RefPtr<ScaledFont> font =
+    Factory::CreateScaledFontForNativeFont(nativeFont, aSize);
+
+#ifdef USE_CAIRO_SCALED_FONT
+  static_cast<ScaledFontBase*>(font.get())->PopulateCairoScaledFont();
+#endif
+
+  return font.forget();
+}
+
 AntialiasMode
 ScaledFontWin::GetDefaultAAMode()
 {
diff --git a/gfx/2d/ScaledFontWin.h b/gfx/2d/ScaledFontWin.h
index c07b263d7285..fe5816707d00 100644
--- a/gfx/2d/ScaledFontWin.h
+++ b/gfx/2d/ScaledFontWin.h
@@ -25,6 +25,10 @@ public:
   bool GetFontInstanceData(FontInstanceDataOutput aCb, void* aBaton) override;
 
   virtual bool GetFontDescriptor(FontDescriptorOutput aCb, void* aBaton) override;
+
+  static already_AddRefed<ScaledFont>
+    CreateFromFontDescriptor(const uint8_t* aData, uint32_t aDataLength, Float aSize);
+
   virtual AntialiasMode GetDefaultAAMode() override;
 
 #ifdef USE_SKIA
diff --git a/gfx/2d/moz.build b/gfx/2d/moz.build
index ad095503d97e..545ac6823390 100644
--- a/gfx/2d/moz.build
+++ b/gfx/2d/moz.build
@@ -91,6 +91,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'windows':
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3'):
     SOURCES += [
+        'NativeFontResourceFontconfig.cpp',
         'ScaledFontFontconfig.cpp',
     ]
 





More information about the tbb-commits mailing list