forked from mirrors/gecko-dev
		
	 c25b3b246f
			
		
	
	
		c25b3b246f
		
	
	
	
	
		
			
			See comments in the bug for reasoning. macOS hasn't used subpixel AA for quite a while. Emulating this macOS AA on vibrant backgrounds was the only point of this feature. This allows to simplify the WebRender code quite a bit, too. Differential Revision: https://phabricator.services.mozilla.com/D192311
		
			
				
	
	
		
			549 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			549 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- 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 "ScaledFontFontconfig.h"
 | |
| #include "UnscaledFontFreeType.h"
 | |
| #include "Logging.h"
 | |
| #include "mozilla/StaticPrefs_gfx.h"
 | |
| #include "mozilla/webrender/WebRenderTypes.h"
 | |
| 
 | |
| #include "skia/include/ports/SkTypeface_cairo.h"
 | |
| #include "HelpersSkia.h"
 | |
| 
 | |
| #include <fontconfig/fcfreetype.h>
 | |
| 
 | |
| #include FT_LCD_FILTER_H
 | |
| #include FT_MULTIPLE_MASTERS_H
 | |
| 
 | |
| namespace mozilla::gfx {
 | |
| 
 | |
| ScaledFontFontconfig::ScaledFontFontconfig(
 | |
|     RefPtr<SharedFTFace>&& aFace, FcPattern* aPattern,
 | |
|     const RefPtr<UnscaledFont>& aUnscaledFont, Float aSize)
 | |
|     : ScaledFontBase(aUnscaledFont, aSize),
 | |
|       mFace(std::move(aFace)),
 | |
|       mInstanceData(aPattern) {}
 | |
| 
 | |
| ScaledFontFontconfig::ScaledFontFontconfig(
 | |
|     RefPtr<SharedFTFace>&& aFace, const InstanceData& aInstanceData,
 | |
|     const RefPtr<UnscaledFont>& aUnscaledFont, Float aSize)
 | |
|     : ScaledFontBase(aUnscaledFont, aSize),
 | |
|       mFace(std::move(aFace)),
 | |
|       mInstanceData(aInstanceData) {}
 | |
| 
 | |
| bool ScaledFontFontconfig::UseSubpixelPosition() const {
 | |
|   return !MOZ_UNLIKELY(
 | |
|              StaticPrefs::
 | |
|                  gfx_text_subpixel_position_force_disabled_AtStartup()) &&
 | |
|          mInstanceData.mAntialias != AntialiasMode::NONE &&
 | |
|          FT_IS_SCALABLE(mFace->GetFace()) &&
 | |
|          (mInstanceData.mHinting == FontHinting::NONE ||
 | |
|           mInstanceData.mHinting == FontHinting::LIGHT ||
 | |
|           MOZ_UNLIKELY(
 | |
|               StaticPrefs::
 | |
|                   gfx_text_subpixel_position_force_enabled_AtStartup()));
 | |
| }
 | |
| 
 | |
| SkTypeface* ScaledFontFontconfig::CreateSkTypeface() {
 | |
|   SkPixelGeometry geo = mInstanceData.mFlags & InstanceData::SUBPIXEL_BGR
 | |
|                             ? (mInstanceData.mFlags & InstanceData::LCD_VERTICAL
 | |
|                                    ? kBGR_V_SkPixelGeometry
 | |
|                                    : kBGR_H_SkPixelGeometry)
 | |
|                             : (mInstanceData.mFlags & InstanceData::LCD_VERTICAL
 | |
|                                    ? kRGB_V_SkPixelGeometry
 | |
|                                    : kRGB_H_SkPixelGeometry);
 | |
|   return SkCreateTypefaceFromCairoFTFont(mFace->GetFace(), mFace.get(), geo,
 | |
|                                          mInstanceData.mLcdFilter);
 | |
| }
 | |
| 
 | |
| void ScaledFontFontconfig::SetupSkFontDrawOptions(SkFont& aFont) {
 | |
|   aFont.setSubpixel(UseSubpixelPosition());
 | |
| 
 | |
|   if (mInstanceData.mFlags & InstanceData::AUTOHINT) {
 | |
|     aFont.setForceAutoHinting(true);
 | |
|   }
 | |
|   if (mInstanceData.mFlags & InstanceData::EMBEDDED_BITMAP) {
 | |
|     aFont.setEmbeddedBitmaps(true);
 | |
|   }
 | |
|   if (mInstanceData.mFlags & InstanceData::EMBOLDEN) {
 | |
|     aFont.setEmbolden(true);
 | |
|   }
 | |
| 
 | |
|   aFont.setHinting(GfxHintingToSkiaHinting(mInstanceData.mHinting));
 | |
| }
 | |
| 
 | |
| bool ScaledFontFontconfig::MayUseBitmaps() {
 | |
|   return mInstanceData.mFlags & InstanceData::EMBEDDED_BITMAP &&
 | |
|          !FT_IS_SCALABLE(mFace->GetFace());
 | |
| }
 | |
| 
 | |
| cairo_font_face_t* ScaledFontFontconfig::CreateCairoFontFace(
 | |
|     cairo_font_options_t* aFontOptions) {
 | |
|   int loadFlags;
 | |
|   unsigned int synthFlags;
 | |
|   mInstanceData.SetupFontOptions(aFontOptions, &loadFlags, &synthFlags);
 | |
| 
 | |
|   return cairo_ft_font_face_create_for_ft_face(mFace->GetFace(), loadFlags,
 | |
|                                                synthFlags, mFace.get());
 | |
| }
 | |
| 
 | |
| AntialiasMode ScaledFontFontconfig::GetDefaultAAMode() {
 | |
|   return mInstanceData.mAntialias;
 | |
| }
 | |
| 
 | |
| bool FcPatternAllowsBitmaps(FcPattern* aPattern, bool aAntialias,
 | |
|                             bool aHinting) {
 | |
|   if (!aAntialias) {
 | |
|     // Always allow bitmaps when antialiasing is disabled
 | |
|     return true;
 | |
|   }
 | |
|   FcBool bitmap;
 | |
|   if (FcPatternGetBool(aPattern, FC_EMBEDDED_BITMAP, 0, &bitmap) !=
 | |
|           FcResultMatch ||
 | |
|       !bitmap) {
 | |
|     // If bitmaps were explicitly disabled, then disallow them
 | |
|     return false;
 | |
|   }
 | |
|   if (aHinting) {
 | |
|     // If hinting is used and bitmaps were enabled, then allow them
 | |
|     return true;
 | |
|   }
 | |
|   // When hinting is disabled, then avoid loading bitmaps from outline
 | |
|   // fonts. However, emoji fonts may have no outlines while containing
 | |
|   // bitmaps intended to be scaled, so still allow those.
 | |
|   FcBool outline;
 | |
|   if (FcPatternGetBool(aPattern, FC_OUTLINE, 0, &outline) == FcResultMatch &&
 | |
|       outline) {
 | |
|     return false;
 | |
|   }
 | |
|   FcBool scalable;
 | |
|   if (FcPatternGetBool(aPattern, FC_SCALABLE, 0, &scalable) != FcResultMatch ||
 | |
|       !scalable) {
 | |
|     return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| ScaledFontFontconfig::InstanceData::InstanceData(FcPattern* aPattern)
 | |
|     : mFlags(0),
 | |
|       mAntialias(AntialiasMode::NONE),
 | |
|       mHinting(FontHinting::NONE),
 | |
|       mLcdFilter(FT_LCD_FILTER_LEGACY) {
 | |
|   // Record relevant Fontconfig properties into instance data.
 | |
|   FcBool autohint;
 | |
|   if (FcPatternGetBool(aPattern, FC_AUTOHINT, 0, &autohint) == FcResultMatch &&
 | |
|       autohint) {
 | |
|     mFlags |= AUTOHINT;
 | |
|   }
 | |
|   FcBool embolden;
 | |
|   if (FcPatternGetBool(aPattern, FC_EMBOLDEN, 0, &embolden) == FcResultMatch &&
 | |
|       embolden) {
 | |
|     mFlags |= EMBOLDEN;
 | |
|   }
 | |
| 
 | |
|   // For printer fonts, Cairo hint metrics and hinting will be disabled.
 | |
|   // For other fonts, allow hint metrics and hinting.
 | |
|   FcBool printing;
 | |
|   if (FcPatternGetBool(aPattern, "gfx.printing", 0, &printing) !=
 | |
|           FcResultMatch ||
 | |
|       !printing) {
 | |
|     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;
 | |
|       }
 | |
|       switch (hintstyle) {
 | |
|         case FC_HINT_SLIGHT:
 | |
|           mHinting = FontHinting::LIGHT;
 | |
|           break;
 | |
|         case FC_HINT_MEDIUM:
 | |
|           mHinting = FontHinting::NORMAL;
 | |
|           break;
 | |
|         case FC_HINT_FULL:
 | |
|           mHinting = FontHinting::FULL;
 | |
|           break;
 | |
|         case FC_HINT_NONE:
 | |
|         default:
 | |
|           break;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   FcBool antialias;
 | |
|   if (FcPatternGetBool(aPattern, FC_ANTIALIAS, 0, &antialias) ==
 | |
|           FcResultMatch &&
 | |
|       !antialias) {
 | |
|     // If AA is explicitly disabled, leave bitmaps enabled.
 | |
|     mFlags |= EMBEDDED_BITMAP;
 | |
|   } else {
 | |
|     mAntialias = AntialiasMode::GRAY;
 | |
| 
 | |
|     // Otherwise, if AA is enabled, disable embedded bitmaps unless explicitly
 | |
|     // enabled.
 | |
|     if (FcPatternAllowsBitmaps(aPattern, true, mHinting != FontHinting::NONE)) {
 | |
|       mFlags |= EMBEDDED_BITMAP;
 | |
|     }
 | |
| 
 | |
|     // Only record subpixel order and lcd filtering if antialiasing is enabled.
 | |
|     int rgba;
 | |
|     if (mFlags & HINT_METRICS &&
 | |
|         FcPatternGetInteger(aPattern, FC_RGBA, 0, &rgba) == FcResultMatch) {
 | |
|       switch (rgba) {
 | |
|         case FC_RGBA_RGB:
 | |
|         case FC_RGBA_BGR:
 | |
|         case FC_RGBA_VRGB:
 | |
|         case FC_RGBA_VBGR:
 | |
|           mAntialias = AntialiasMode::SUBPIXEL;
 | |
|           if (rgba == FC_RGBA_VRGB || rgba == FC_RGBA_VBGR) {
 | |
|             mFlags |= LCD_VERTICAL;
 | |
|           }
 | |
|           if (rgba == FC_RGBA_BGR || rgba == FC_RGBA_VBGR) {
 | |
|             mFlags |= SUBPIXEL_BGR;
 | |
|           }
 | |
|           break;
 | |
|         case FC_RGBA_NONE:
 | |
|         case FC_RGBA_UNKNOWN:
 | |
|         default:
 | |
|           break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     int filter;
 | |
|     if (mAntialias == AntialiasMode::SUBPIXEL &&
 | |
|         FcPatternGetInteger(aPattern, FC_LCD_FILTER, 0, &filter) ==
 | |
|             FcResultMatch) {
 | |
|       switch (filter) {
 | |
|         case FC_LCD_NONE:
 | |
|           mLcdFilter = FT_LCD_FILTER_NONE;
 | |
|           break;
 | |
|         case FC_LCD_DEFAULT:
 | |
|           mLcdFilter = FT_LCD_FILTER_DEFAULT;
 | |
|           break;
 | |
|         case FC_LCD_LIGHT:
 | |
|           mLcdFilter = FT_LCD_FILTER_LIGHT;
 | |
|           break;
 | |
|         case FC_LCD_LEGACY:
 | |
|         default:
 | |
|           break;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| ScaledFontFontconfig::InstanceData::InstanceData(
 | |
|     const wr::FontInstanceOptions* aOptions,
 | |
|     const wr::FontInstancePlatformOptions* aPlatformOptions)
 | |
|     : mFlags(HINT_METRICS),
 | |
|       mAntialias(AntialiasMode::NONE),
 | |
|       mHinting(FontHinting::FULL),
 | |
|       mLcdFilter(FT_LCD_FILTER_LEGACY) {
 | |
|   if (aOptions) {
 | |
|     if (aOptions->flags & wr::FontInstanceFlags::FORCE_AUTOHINT) {
 | |
|       mFlags |= AUTOHINT;
 | |
|     }
 | |
|     if (aOptions->flags & wr::FontInstanceFlags::EMBEDDED_BITMAPS) {
 | |
|       mFlags |= EMBEDDED_BITMAP;
 | |
|     }
 | |
|     if (aOptions->flags & wr::FontInstanceFlags::SYNTHETIC_BOLD) {
 | |
|       mFlags |= EMBOLDEN;
 | |
|     }
 | |
|     if (aOptions->render_mode == wr::FontRenderMode::Subpixel) {
 | |
|       mAntialias = AntialiasMode::SUBPIXEL;
 | |
|       if (aOptions->flags & wr::FontInstanceFlags::SUBPIXEL_BGR) {
 | |
|         mFlags |= SUBPIXEL_BGR;
 | |
|       }
 | |
|       if (aOptions->flags & wr::FontInstanceFlags::LCD_VERTICAL) {
 | |
|         mFlags |= LCD_VERTICAL;
 | |
|       }
 | |
|     } else if (aOptions->render_mode != wr::FontRenderMode::Mono) {
 | |
|       mAntialias = AntialiasMode::GRAY;
 | |
|     }
 | |
|   }
 | |
|   if (aPlatformOptions) {
 | |
|     switch (aPlatformOptions->hinting) {
 | |
|       case wr::FontHinting::None:
 | |
|         mHinting = FontHinting::NONE;
 | |
|         break;
 | |
|       case wr::FontHinting::Light:
 | |
|         mHinting = FontHinting::LIGHT;
 | |
|         break;
 | |
|       case wr::FontHinting::Normal:
 | |
|         mHinting = FontHinting::NORMAL;
 | |
|         break;
 | |
|       default:
 | |
|         break;
 | |
|     }
 | |
|     switch (aPlatformOptions->lcd_filter) {
 | |
|       case wr::FontLCDFilter::None:
 | |
|         mLcdFilter = FT_LCD_FILTER_NONE;
 | |
|         break;
 | |
|       case wr::FontLCDFilter::Default:
 | |
|         mLcdFilter = FT_LCD_FILTER_DEFAULT;
 | |
|         break;
 | |
|       case wr::FontLCDFilter::Light:
 | |
|         mLcdFilter = FT_LCD_FILTER_LIGHT;
 | |
|         break;
 | |
|       default:
 | |
|         break;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| void ScaledFontFontconfig::InstanceData::SetupFontOptions(
 | |
|     cairo_font_options_t* aFontOptions, int* aOutLoadFlags,
 | |
|     unsigned int* aOutSynthFlags) const {
 | |
|   // For regular (non-printer) fonts, enable hint metrics as well as hinting
 | |
|   // and (possibly subpixel) antialiasing.
 | |
|   cairo_font_options_set_hint_metrics(
 | |
|       aFontOptions,
 | |
|       mFlags & HINT_METRICS ? CAIRO_HINT_METRICS_ON : CAIRO_HINT_METRICS_OFF);
 | |
| 
 | |
|   cairo_hint_style_t hinting;
 | |
|   switch (mHinting) {
 | |
|     case FontHinting::NONE:
 | |
|       hinting = CAIRO_HINT_STYLE_NONE;
 | |
|       break;
 | |
|     case FontHinting::LIGHT:
 | |
|       hinting = CAIRO_HINT_STYLE_SLIGHT;
 | |
|       break;
 | |
|     case FontHinting::NORMAL:
 | |
|       hinting = CAIRO_HINT_STYLE_MEDIUM;
 | |
|       break;
 | |
|     case FontHinting::FULL:
 | |
|       hinting = CAIRO_HINT_STYLE_FULL;
 | |
|       break;
 | |
|   }
 | |
|   cairo_font_options_set_hint_style(aFontOptions, hinting);
 | |
| 
 | |
|   switch (mAntialias) {
 | |
|     case AntialiasMode::NONE:
 | |
|       cairo_font_options_set_antialias(aFontOptions, CAIRO_ANTIALIAS_NONE);
 | |
|       break;
 | |
|     case AntialiasMode::GRAY:
 | |
|     default:
 | |
|       cairo_font_options_set_antialias(aFontOptions, CAIRO_ANTIALIAS_GRAY);
 | |
|       break;
 | |
|     case AntialiasMode::SUBPIXEL: {
 | |
|       cairo_font_options_set_antialias(aFontOptions, CAIRO_ANTIALIAS_SUBPIXEL);
 | |
|       cairo_font_options_set_subpixel_order(
 | |
|           aFontOptions,
 | |
|           mFlags & SUBPIXEL_BGR
 | |
|               ? (mFlags & LCD_VERTICAL ? CAIRO_SUBPIXEL_ORDER_VBGR
 | |
|                                        : CAIRO_SUBPIXEL_ORDER_BGR)
 | |
|               : (mFlags & LCD_VERTICAL ? CAIRO_SUBPIXEL_ORDER_VRGB
 | |
|                                        : CAIRO_SUBPIXEL_ORDER_RGB));
 | |
|       cairo_lcd_filter_t lcdFilter = CAIRO_LCD_FILTER_DEFAULT;
 | |
|       switch (mLcdFilter) {
 | |
|         case FT_LCD_FILTER_NONE:
 | |
|           lcdFilter = CAIRO_LCD_FILTER_NONE;
 | |
|           break;
 | |
|         case FT_LCD_FILTER_DEFAULT:
 | |
|           lcdFilter = CAIRO_LCD_FILTER_FIR5;
 | |
|           break;
 | |
|         case FT_LCD_FILTER_LIGHT:
 | |
|           lcdFilter = CAIRO_LCD_FILTER_FIR3;
 | |
|           break;
 | |
|         case FT_LCD_FILTER_LEGACY:
 | |
|           lcdFilter = CAIRO_LCD_FILTER_INTRA_PIXEL;
 | |
|           break;
 | |
|       }
 | |
|       cairo_font_options_set_lcd_filter(aFontOptions, lcdFilter);
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Try to build a sane initial set of Cairo font options based on the
 | |
|   // Fontconfig pattern.
 | |
|   int loadFlags = FT_LOAD_DEFAULT;
 | |
|   unsigned int synthFlags = 0;
 | |
| 
 | |
|   if (!(mFlags & EMBEDDED_BITMAP)) {
 | |
|     loadFlags |= FT_LOAD_NO_BITMAP;
 | |
|   }
 | |
|   if (mFlags & AUTOHINT) {
 | |
|     loadFlags |= FT_LOAD_FORCE_AUTOHINT;
 | |
|   }
 | |
|   if (mFlags & EMBOLDEN) {
 | |
|     synthFlags |= CAIRO_FT_SYNTHESIZE_BOLD;
 | |
|   }
 | |
| 
 | |
|   *aOutLoadFlags = loadFlags;
 | |
|   *aOutSynthFlags = synthFlags;
 | |
| }
 | |
| 
 | |
| bool ScaledFontFontconfig::GetFontInstanceData(FontInstanceDataOutput aCb,
 | |
|                                                void* aBaton) {
 | |
|   std::vector<FontVariation> variations;
 | |
|   if (HasVariationSettings()) {
 | |
|     UnscaledFontFreeType::GetVariationSettingsFromFace(&variations,
 | |
|                                                        mFace->GetFace());
 | |
|   }
 | |
| 
 | |
|   aCb(reinterpret_cast<uint8_t*>(&mInstanceData), sizeof(mInstanceData),
 | |
|       variations.data(), variations.size(), aBaton);
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool ScaledFontFontconfig::GetWRFontInstanceOptions(
 | |
|     Maybe<wr::FontInstanceOptions>* aOutOptions,
 | |
|     Maybe<wr::FontInstancePlatformOptions>* aOutPlatformOptions,
 | |
|     std::vector<FontVariation>* aOutVariations) {
 | |
|   wr::FontInstanceOptions options;
 | |
|   options.render_mode = wr::FontRenderMode::Alpha;
 | |
|   options.flags = wr::FontInstanceFlags{0};
 | |
|   if (UseSubpixelPosition()) {
 | |
|     options.flags |= wr::FontInstanceFlags::SUBPIXEL_POSITION;
 | |
|   }
 | |
|   options.synthetic_italics =
 | |
|       wr::DegreesToSyntheticItalics(GetSyntheticObliqueAngle());
 | |
| 
 | |
|   wr::FontInstancePlatformOptions platformOptions;
 | |
|   platformOptions.lcd_filter = wr::FontLCDFilter::Legacy;
 | |
|   platformOptions.hinting = wr::FontHinting::Normal;
 | |
| 
 | |
|   if (mInstanceData.mFlags & InstanceData::AUTOHINT) {
 | |
|     options.flags |= wr::FontInstanceFlags::FORCE_AUTOHINT;
 | |
|   }
 | |
|   if (mInstanceData.mFlags & InstanceData::EMBOLDEN) {
 | |
|     options.flags |= wr::FontInstanceFlags::SYNTHETIC_BOLD;
 | |
|   }
 | |
|   if (mInstanceData.mFlags & InstanceData::EMBEDDED_BITMAP) {
 | |
|     options.flags |= wr::FontInstanceFlags::EMBEDDED_BITMAPS;
 | |
|   }
 | |
|   if (mInstanceData.mAntialias != AntialiasMode::NONE) {
 | |
|     if (mInstanceData.mAntialias == AntialiasMode::SUBPIXEL) {
 | |
|       options.render_mode = wr::FontRenderMode::Subpixel;
 | |
|       platformOptions.hinting = wr::FontHinting::LCD;
 | |
|       if (mInstanceData.mFlags & InstanceData::LCD_VERTICAL) {
 | |
|         options.flags |= wr::FontInstanceFlags::LCD_VERTICAL;
 | |
|       }
 | |
|       if (mInstanceData.mFlags & InstanceData::SUBPIXEL_BGR) {
 | |
|         options.flags |= wr::FontInstanceFlags::SUBPIXEL_BGR;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     switch (mInstanceData.mLcdFilter) {
 | |
|       case FT_LCD_FILTER_NONE:
 | |
|         platformOptions.lcd_filter = wr::FontLCDFilter::None;
 | |
|         break;
 | |
|       case FT_LCD_FILTER_DEFAULT:
 | |
|         platformOptions.lcd_filter = wr::FontLCDFilter::Default;
 | |
|         break;
 | |
|       case FT_LCD_FILTER_LIGHT:
 | |
|         platformOptions.lcd_filter = wr::FontLCDFilter::Light;
 | |
|         break;
 | |
|       case FT_LCD_FILTER_LEGACY:
 | |
|       default:
 | |
|         break;
 | |
|     }
 | |
| 
 | |
|     switch (mInstanceData.mHinting) {
 | |
|       case FontHinting::NONE:
 | |
|         platformOptions.hinting = wr::FontHinting::None;
 | |
|         break;
 | |
|       case FontHinting::LIGHT:
 | |
|         platformOptions.hinting = wr::FontHinting::Light;
 | |
|         break;
 | |
|       case FontHinting::NORMAL:
 | |
|         platformOptions.hinting = wr::FontHinting::Normal;
 | |
|         break;
 | |
|       case FontHinting::FULL:
 | |
|         break;
 | |
|     }
 | |
|   } else {
 | |
|     options.render_mode = wr::FontRenderMode::Mono;
 | |
| 
 | |
|     switch (mInstanceData.mHinting) {
 | |
|       case FontHinting::NONE:
 | |
|         platformOptions.hinting = wr::FontHinting::None;
 | |
|         break;
 | |
|       default:
 | |
|         platformOptions.hinting = wr::FontHinting::Mono;
 | |
|         break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   *aOutOptions = Some(options);
 | |
|   *aOutPlatformOptions = Some(platformOptions);
 | |
| 
 | |
|   if (HasVariationSettings()) {
 | |
|     UnscaledFontFreeType::GetVariationSettingsFromFace(aOutVariations,
 | |
|                                                        mFace->GetFace());
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| already_AddRefed<ScaledFont> UnscaledFontFontconfig::CreateScaledFont(
 | |
|     Float aSize, const uint8_t* aInstanceData, uint32_t aInstanceDataLength,
 | |
|     const FontVariation* aVariations, uint32_t aNumVariations) {
 | |
|   if (aInstanceDataLength < sizeof(ScaledFontFontconfig::InstanceData)) {
 | |
|     gfxWarning() << "Fontconfig scaled font instance data is truncated.";
 | |
|     return nullptr;
 | |
|   }
 | |
|   const ScaledFontFontconfig::InstanceData& instanceData =
 | |
|       *reinterpret_cast<const ScaledFontFontconfig::InstanceData*>(
 | |
|           aInstanceData);
 | |
| 
 | |
|   RefPtr<SharedFTFace> face(InitFace());
 | |
|   if (!face) {
 | |
|     gfxWarning() << "Attempted to deserialize Fontconfig scaled font without "
 | |
|                     "FreeType face";
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   if (aNumVariations > 0 && face->GetData()) {
 | |
|     if (RefPtr<SharedFTFace> varFace = face->GetData()->CloneFace()) {
 | |
|       face = varFace;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Only apply variations if we have an explicitly cloned face.
 | |
|   if (aNumVariations > 0 && face != GetFace()) {
 | |
|     ApplyVariationsToFace(aVariations, aNumVariations, face->GetFace());
 | |
|   }
 | |
| 
 | |
|   RefPtr<ScaledFontFontconfig> scaledFont =
 | |
|       new ScaledFontFontconfig(std::move(face), instanceData, this, aSize);
 | |
| 
 | |
|   return scaledFont.forget();
 | |
| }
 | |
| 
 | |
| already_AddRefed<ScaledFont> UnscaledFontFontconfig::CreateScaledFontFromWRFont(
 | |
|     Float aGlyphSize, const wr::FontInstanceOptions* aOptions,
 | |
|     const wr::FontInstancePlatformOptions* aPlatformOptions,
 | |
|     const FontVariation* aVariations, uint32_t aNumVariations) {
 | |
|   ScaledFontFontconfig::InstanceData instanceData(aOptions, aPlatformOptions);
 | |
|   return CreateScaledFont(aGlyphSize, reinterpret_cast<uint8_t*>(&instanceData),
 | |
|                           sizeof(instanceData), aVariations, aNumVariations);
 | |
| }
 | |
| 
 | |
| bool ScaledFontFontconfig::HasVariationSettings() {
 | |
|   // Check if the FT face has been cloned.
 | |
|   return mFace &&
 | |
|          mFace->GetFace()->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS &&
 | |
|          mFace != static_cast<UnscaledFontFontconfig*>(mUnscaledFont.get())
 | |
|                       ->GetFace();
 | |
| }
 | |
| 
 | |
| already_AddRefed<UnscaledFont> UnscaledFontFontconfig::CreateFromFontDescriptor(
 | |
|     const uint8_t* aData, uint32_t aDataLength, uint32_t aIndex) {
 | |
|   if (aDataLength == 0) {
 | |
|     gfxWarning() << "Fontconfig font descriptor is truncated.";
 | |
|     return nullptr;
 | |
|   }
 | |
|   const char* path = reinterpret_cast<const char*>(aData);
 | |
|   RefPtr<UnscaledFont> unscaledFont =
 | |
|       new UnscaledFontFontconfig(std::string(path, aDataLength), aIndex);
 | |
|   return unscaledFont.forget();
 | |
| }
 | |
| 
 | |
| }  // namespace mozilla::gfx
 |