Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/2d/ScaledFontFontconfig.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "ScaledFontFontconfig.h"
8
#include "UnscaledFontFreeType.h"
9
#include "NativeFontResourceFreeType.h"
10
#include "Logging.h"
11
#include "StackArray.h"
12
#include "mozilla/webrender/WebRenderTypes.h"
13
14
#ifdef USE_SKIA
15
#include "skia/include/ports/SkTypeface_cairo.h"
16
#endif
17
18
#include <fontconfig/fcfreetype.h>
19
20
#include FT_MULTIPLE_MASTERS_H
21
22
namespace mozilla {
23
namespace gfx {
24
25
// On Linux and Android our "platform" font is a cairo_scaled_font_t and we use
26
// an SkFontHost implementation that allows Skia to render using this.
27
// This is mainly because FT_Face is not good for sharing between libraries, which
28
// is a requirement when we consider runtime switchable backends and so on
29
ScaledFontFontconfig::ScaledFontFontconfig(cairo_scaled_font_t* aScaledFont,
30
                                           FcPattern* aPattern,
31
                                           const RefPtr<UnscaledFont>& aUnscaledFont,
32
                                           Float aSize)
33
  : ScaledFontBase(aUnscaledFont, aSize)
34
  , mPattern(aPattern)
35
0
{
36
0
  SetCairoScaledFont(aScaledFont);
37
0
  FcPatternReference(aPattern);
38
0
}
39
40
ScaledFontFontconfig::~ScaledFontFontconfig()
41
0
{
42
0
  FcPatternDestroy(mPattern);
43
0
}
44
45
#ifdef USE_SKIA
46
SkTypeface* ScaledFontFontconfig::CreateSkTypeface()
47
0
{
48
0
  return SkCreateTypefaceFromCairoFTFontWithFontconfig(mScaledFont, mPattern);
49
0
}
50
#endif
51
52
ScaledFontFontconfig::InstanceData::InstanceData(cairo_scaled_font_t* aScaledFont, FcPattern* aPattern)
53
  : mFlags(0)
54
  , mHintStyle(FC_HINT_NONE)
55
  , mSubpixelOrder(FC_RGBA_UNKNOWN)
56
  , mLcdFilter(FC_LCD_LEGACY)
57
0
{
58
0
  // Record relevant Fontconfig properties into instance data.
59
0
  FcBool autohint;
60
0
  if (FcPatternGetBool(aPattern, FC_AUTOHINT, 0, &autohint) == FcResultMatch && autohint) {
61
0
    mFlags |= AUTOHINT;
62
0
  }
63
0
  FcBool bitmap;
64
0
  if (FcPatternGetBool(aPattern, FC_EMBEDDED_BITMAP, 0, &bitmap) == FcResultMatch && bitmap) {
65
0
    mFlags |= EMBEDDED_BITMAP;
66
0
  }
67
0
  FcBool embolden;
68
0
  if (FcPatternGetBool(aPattern, FC_EMBOLDEN, 0, &embolden) == FcResultMatch && embolden) {
69
0
    mFlags |= EMBOLDEN;
70
0
  }
71
0
  FcBool vertical;
72
0
  if (FcPatternGetBool(aPattern, FC_VERTICAL_LAYOUT, 0, &vertical) == FcResultMatch && vertical) {
73
0
    mFlags |= VERTICAL_LAYOUT;
74
0
  }
75
0
76
0
  FcBool antialias;
77
0
  if (FcPatternGetBool(aPattern, FC_ANTIALIAS, 0, &antialias) != FcResultMatch || antialias) {
78
0
    mFlags |= ANTIALIAS;
79
0
80
0
    // Only record subpixel order and lcd filtering if antialiasing is enabled.
81
0
    int rgba;
82
0
    if (FcPatternGetInteger(aPattern, FC_RGBA, 0, &rgba) == FcResultMatch) {
83
0
      mSubpixelOrder = rgba;
84
0
    }
85
0
    int filter;
86
0
    if (FcPatternGetInteger(aPattern, FC_LCD_FILTER, 0, &filter) == FcResultMatch) {
87
0
      mLcdFilter = filter;
88
0
    }
89
0
  }
90
0
91
0
  cairo_font_options_t* fontOptions = cairo_font_options_create();
92
0
  cairo_scaled_font_get_font_options(aScaledFont, fontOptions);
93
0
  // For printer fonts, Cairo hint metrics and hinting will be disabled.
94
0
  // For other fonts, allow hint metrics and hinting.
95
0
  if (cairo_font_options_get_hint_metrics(fontOptions) != CAIRO_HINT_METRICS_OFF) {
96
0
    mFlags |= HINT_METRICS;
97
0
98
0
    FcBool hinting;
99
0
    if (FcPatternGetBool(aPattern, FC_HINTING, 0, &hinting) != FcResultMatch || hinting) {
100
0
      int hintstyle;
101
0
      if (FcPatternGetInteger(aPattern, FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch) {
102
0
        hintstyle = FC_HINT_FULL;
103
0
      }
104
0
      mHintStyle = hintstyle;
105
0
    }
106
0
  }
107
0
  cairo_font_options_destroy(fontOptions);
108
0
}
109
110
ScaledFontFontconfig::InstanceData::InstanceData(const wr::FontInstanceOptions* aOptions,
111
                                                 const wr::FontInstancePlatformOptions* aPlatformOptions)
112
  : mFlags(HINT_METRICS)
113
  , mHintStyle(FC_HINT_FULL)
114
  , mSubpixelOrder(FC_RGBA_UNKNOWN)
115
  , mLcdFilter(FC_LCD_LEGACY)
116
0
{
117
0
  if (aOptions) {
118
0
    if (aOptions->flags & wr::FontInstanceFlags::FORCE_AUTOHINT) {
119
0
      mFlags |= AUTOHINT;
120
0
    }
121
0
    if (aOptions->flags & wr::FontInstanceFlags::EMBEDDED_BITMAPS) {
122
0
      mFlags |= EMBEDDED_BITMAP;
123
0
    }
124
0
    if (aOptions->flags & wr::FontInstanceFlags::SYNTHETIC_BOLD) {
125
0
      mFlags |= EMBOLDEN;
126
0
    }
127
0
    if (aOptions->flags & wr::FontInstanceFlags::VERTICAL_LAYOUT) {
128
0
      mFlags |= VERTICAL_LAYOUT;
129
0
    }
130
0
    if (aOptions->render_mode != wr::FontRenderMode::Mono) {
131
0
      mFlags |= ANTIALIAS;
132
0
      if (aOptions->render_mode == wr::FontRenderMode::Subpixel) {
133
0
        if (aOptions->flags & wr::FontInstanceFlags::SUBPIXEL_BGR) {
134
0
          mSubpixelOrder =
135
0
            aOptions->flags & wr::FontInstanceFlags::LCD_VERTICAL ? FC_RGBA_VBGR : FC_RGBA_BGR;
136
0
        } else {
137
0
          mSubpixelOrder =
138
0
            aOptions->flags & wr::FontInstanceFlags::LCD_VERTICAL ? FC_RGBA_VRGB : FC_RGBA_RGB;
139
0
        }
140
0
      }
141
0
    }
142
0
  }
143
0
  if (aPlatformOptions) {
144
0
    switch (aPlatformOptions->hinting) {
145
0
    case wr::FontHinting::None:
146
0
      mHintStyle = FC_HINT_NONE;
147
0
      break;
148
0
    case wr::FontHinting::Light:
149
0
      mHintStyle = FC_HINT_SLIGHT;
150
0
      break;
151
0
    case wr::FontHinting::Normal:
152
0
      mHintStyle = FC_HINT_MEDIUM;
153
0
      break;
154
0
    default:
155
0
      break;
156
0
    }
157
0
    switch (aPlatformOptions->lcd_filter) {
158
0
    case wr::FontLCDFilter::None:
159
0
      mLcdFilter = FC_LCD_NONE;
160
0
      break;
161
0
    case wr::FontLCDFilter::Default:
162
0
      mLcdFilter = FC_LCD_DEFAULT;
163
0
      break;
164
0
    case wr::FontLCDFilter::Light:
165
0
      mLcdFilter = FC_LCD_LIGHT;
166
0
      break;
167
0
    default:
168
0
      break;
169
0
    }
170
0
  }
171
0
}
172
173
void
174
ScaledFontFontconfig::InstanceData::SetupPattern(FcPattern* aPattern) const
175
0
{
176
0
  if (mFlags & AUTOHINT) {
177
0
    FcPatternAddBool(aPattern, FC_AUTOHINT, FcTrue);
178
0
  }
179
0
  if (mFlags & EMBEDDED_BITMAP) {
180
0
    FcPatternAddBool(aPattern, FC_EMBEDDED_BITMAP, FcTrue);
181
0
  }
182
0
  if (mFlags & EMBOLDEN) {
183
0
    FcPatternAddBool(aPattern, FC_EMBOLDEN, FcTrue);
184
0
  }
185
0
  if (mFlags & VERTICAL_LAYOUT) {
186
0
    FcPatternAddBool(aPattern, FC_VERTICAL_LAYOUT, FcTrue);
187
0
  }
188
0
189
0
  if (mFlags & ANTIALIAS) {
190
0
    FcPatternAddBool(aPattern, FC_ANTIALIAS, FcTrue);
191
0
    if (mSubpixelOrder != FC_RGBA_UNKNOWN) {
192
0
      FcPatternAddInteger(aPattern, FC_RGBA, mSubpixelOrder);
193
0
    }
194
0
    if (mLcdFilter != FC_LCD_LEGACY) {
195
0
      FcPatternAddInteger(aPattern, FC_LCD_FILTER, mLcdFilter);
196
0
    }
197
0
  } else {
198
0
    FcPatternAddBool(aPattern, FC_ANTIALIAS, FcFalse);
199
0
  }
200
0
201
0
  if (mHintStyle) {
202
0
    FcPatternAddBool(aPattern, FC_HINTING, FcTrue);
203
0
    FcPatternAddInteger(aPattern, FC_HINT_STYLE, mHintStyle);
204
0
  } else {
205
0
    FcPatternAddBool(aPattern, FC_HINTING, FcFalse);
206
0
  }
207
0
}
208
209
void
210
ScaledFontFontconfig::InstanceData::SetupFontOptions(cairo_font_options_t* aFontOptions) const
211
0
{
212
0
  // Try to build a sane initial set of Cairo font options based on the Fontconfig
213
0
  // pattern.
214
0
  if (mFlags & HINT_METRICS) {
215
0
    // For regular (non-printer) fonts, enable hint metrics as well as hinting
216
0
    // and (possibly subpixel) antialiasing.
217
0
    cairo_font_options_set_hint_metrics(aFontOptions, CAIRO_HINT_METRICS_ON);
218
0
219
0
    cairo_hint_style_t hinting;
220
0
    switch (mHintStyle) {
221
0
    case FC_HINT_NONE:
222
0
      hinting = CAIRO_HINT_STYLE_NONE;
223
0
      break;
224
0
    case FC_HINT_SLIGHT:
225
0
      hinting = CAIRO_HINT_STYLE_SLIGHT;
226
0
      break;
227
0
    case FC_HINT_MEDIUM:
228
0
    default:
229
0
      hinting = CAIRO_HINT_STYLE_MEDIUM;
230
0
      break;
231
0
    case FC_HINT_FULL:
232
0
      hinting = CAIRO_HINT_STYLE_FULL;
233
0
      break;
234
0
    }
235
0
    cairo_font_options_set_hint_style(aFontOptions, hinting);
236
0
237
0
    if (mFlags & ANTIALIAS) {
238
0
      cairo_subpixel_order_t subpixel = CAIRO_SUBPIXEL_ORDER_DEFAULT;
239
0
      switch (mSubpixelOrder) {
240
0
      case FC_RGBA_RGB:
241
0
        subpixel = CAIRO_SUBPIXEL_ORDER_RGB;
242
0
        break;
243
0
      case FC_RGBA_BGR:
244
0
        subpixel = CAIRO_SUBPIXEL_ORDER_BGR;
245
0
        break;
246
0
      case FC_RGBA_VRGB:
247
0
        subpixel = CAIRO_SUBPIXEL_ORDER_VRGB;
248
0
        break;
249
0
      case FC_RGBA_VBGR:
250
0
        subpixel = CAIRO_SUBPIXEL_ORDER_VBGR;
251
0
        break;
252
0
      default:
253
0
        break;
254
0
      }
255
0
      if (subpixel != CAIRO_SUBPIXEL_ORDER_DEFAULT) {
256
0
        cairo_font_options_set_antialias(aFontOptions, CAIRO_ANTIALIAS_SUBPIXEL);
257
0
        cairo_font_options_set_subpixel_order(aFontOptions, subpixel);
258
0
      } else {
259
0
        cairo_font_options_set_antialias(aFontOptions, CAIRO_ANTIALIAS_GRAY);
260
0
      }
261
0
    } else {
262
0
      cairo_font_options_set_antialias(aFontOptions, CAIRO_ANTIALIAS_NONE);
263
0
    }
264
0
  } else {
265
0
    // For printer fonts, disable hint metrics and hinting. Don't allow subpixel
266
0
    // antialiasing.
267
0
    cairo_font_options_set_hint_metrics(aFontOptions, CAIRO_HINT_METRICS_OFF);
268
0
    cairo_font_options_set_hint_style(aFontOptions, CAIRO_HINT_STYLE_NONE);
269
0
    cairo_font_options_set_antialias(aFontOptions,
270
0
      mFlags & ANTIALIAS ? CAIRO_ANTIALIAS_GRAY : CAIRO_ANTIALIAS_NONE);
271
0
  }
272
0
}
273
274
bool
275
ScaledFontFontconfig::GetFontInstanceData(FontInstanceDataOutput aCb, void* aBaton)
276
0
{
277
0
  InstanceData instance(GetCairoScaledFont(), mPattern);
278
0
279
0
  std::vector<FontVariation> variations;
280
0
  if (HasVariationSettings()) {
281
0
    FT_Face face = nullptr;
282
0
    if (FcPatternGetFTFace(mPattern, FC_FT_FACE, 0, &face) == FcResultMatch) {
283
0
      UnscaledFontFreeType::GetVariationSettingsFromFace(&variations, face);
284
0
    }
285
0
  }
286
0
287
0
  aCb(reinterpret_cast<uint8_t*>(&instance), sizeof(instance),
288
0
      variations.data(), variations.size(), aBaton);
289
0
  return true;
290
0
}
291
292
bool
293
ScaledFontFontconfig::GetWRFontInstanceOptions(Maybe<wr::FontInstanceOptions>* aOutOptions,
294
                                               Maybe<wr::FontInstancePlatformOptions>* aOutPlatformOptions,
295
                                               std::vector<FontVariation>* aOutVariations)
296
0
{
297
0
  wr::FontInstanceOptions options;
298
0
  options.render_mode = wr::FontRenderMode::Alpha;
299
0
  // FIXME: Cairo-FT metrics are not compatible with subpixel positioning.
300
0
  // options.flags = wr::FontInstanceFlags::SUBPIXEL_POSITION;
301
0
  options.flags = 0;
302
0
  options.bg_color = wr::ToColorU(Color());
303
0
  options.synthetic_italics = wr::DegreesToSyntheticItalics(GetSyntheticObliqueAngle());
304
0
305
0
  wr::FontInstancePlatformOptions platformOptions;
306
0
  platformOptions.lcd_filter = wr::FontLCDFilter::Legacy;
307
0
  platformOptions.hinting = wr::FontHinting::Normal;
308
0
309
0
  FcBool autohint;
310
0
  if (FcPatternGetBool(mPattern, FC_AUTOHINT, 0, &autohint) == FcResultMatch && autohint) {
311
0
    options.flags |= wr::FontInstanceFlags::FORCE_AUTOHINT;
312
0
  }
313
0
  FcBool embolden;
314
0
  if (FcPatternGetBool(mPattern, FC_EMBOLDEN, 0, &embolden) == FcResultMatch && embolden) {
315
0
    options.flags |= wr::FontInstanceFlags::SYNTHETIC_BOLD;
316
0
  }
317
0
  FcBool vertical;
318
0
  if (FcPatternGetBool(mPattern, FC_VERTICAL_LAYOUT, 0, &vertical) == FcResultMatch && vertical) {
319
0
    options.flags |= wr::FontInstanceFlags::VERTICAL_LAYOUT;
320
0
  }
321
0
322
0
  FcBool antialias;
323
0
  if (FcPatternGetBool(mPattern, FC_ANTIALIAS, 0, &antialias) != FcResultMatch || antialias) {
324
0
    int rgba;
325
0
    if (FcPatternGetInteger(mPattern, FC_RGBA, 0, &rgba) == FcResultMatch) {
326
0
      switch (rgba) {
327
0
        case FC_RGBA_RGB:
328
0
        case FC_RGBA_BGR:
329
0
        case FC_RGBA_VRGB:
330
0
        case FC_RGBA_VBGR:
331
0
            options.render_mode = wr::FontRenderMode::Subpixel;
332
0
            if (rgba == FC_RGBA_VRGB || rgba == FC_RGBA_VBGR) {
333
0
                options.flags |= wr::FontInstanceFlags::LCD_VERTICAL;
334
0
            }
335
0
            platformOptions.hinting = wr::FontHinting::LCD;
336
0
            if (rgba == FC_RGBA_BGR || rgba == FC_RGBA_VBGR) {
337
0
                options.flags |= wr::FontInstanceFlags::SUBPIXEL_BGR;
338
0
            }
339
0
            break;
340
0
        case FC_RGBA_NONE:
341
0
        case FC_RGBA_UNKNOWN:
342
0
        default:
343
0
          break;
344
0
      }
345
0
    }
346
0
347
0
    if (options.render_mode == wr::FontRenderMode::Subpixel) {
348
0
      int filter;
349
0
      if (FcPatternGetInteger(mPattern, FC_LCD_FILTER, 0, &filter) == FcResultMatch) {
350
0
        switch (filter) {
351
0
        case FC_LCD_NONE:
352
0
          platformOptions.lcd_filter = wr::FontLCDFilter::None;
353
0
          break;
354
0
        case FC_LCD_DEFAULT:
355
0
          platformOptions.lcd_filter = wr::FontLCDFilter::Default;
356
0
          break;
357
0
        case FC_LCD_LIGHT:
358
0
          platformOptions.lcd_filter = wr::FontLCDFilter::Light;
359
0
          break;
360
0
        case FC_LCD_LEGACY:
361
0
        default:
362
0
          break;
363
0
        }
364
0
      }
365
0
    }
366
0
367
0
    // Match cairo-ft's handling of embeddedbitmap:
368
0
    // If AA is explicitly disabled, leave bitmaps enabled.
369
0
    // Otherwise, disable embedded bitmaps unless explicitly enabled.
370
0
    FcBool bitmap;
371
0
    if (FcPatternGetBool(mPattern, FC_EMBEDDED_BITMAP, 0, &bitmap) == FcResultMatch && bitmap) {
372
0
      options.flags |= wr::FontInstanceFlags::EMBEDDED_BITMAPS;
373
0
    }
374
0
  } else {
375
0
    options.render_mode = wr::FontRenderMode::Mono;
376
0
    platformOptions.hinting = wr::FontHinting::Mono;
377
0
    options.flags |= wr::FontInstanceFlags::EMBEDDED_BITMAPS;
378
0
  }
379
0
380
0
  FcBool hinting;
381
0
  int hintstyle;
382
0
  if (FcPatternGetBool(mPattern, FC_HINTING, 0, &hinting) != FcResultMatch || hinting) {
383
0
    if (FcPatternGetInteger(mPattern, FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch) {
384
0
        hintstyle = FC_HINT_FULL;
385
0
    }
386
0
  } else {
387
0
    hintstyle = FC_HINT_NONE;
388
0
  }
389
0
390
0
  if (hintstyle == FC_HINT_NONE) {
391
0
    platformOptions.hinting = wr::FontHinting::None;
392
0
  } else if (options.render_mode != wr::FontRenderMode::Mono) {
393
0
    switch (hintstyle) {
394
0
    case FC_HINT_SLIGHT:
395
0
      platformOptions.hinting = wr::FontHinting::Light;
396
0
      break;
397
0
    case FC_HINT_MEDIUM:
398
0
      platformOptions.hinting = wr::FontHinting::Normal;
399
0
      break;
400
0
    case FC_HINT_FULL:
401
0
    default:
402
0
      break;
403
0
    }
404
0
  }
405
0
406
0
  *aOutOptions = Some(options);
407
0
  *aOutPlatformOptions = Some(platformOptions);
408
0
409
0
  if (HasVariationSettings()) {
410
0
    FT_Face face = nullptr;
411
0
    if (FcPatternGetFTFace(mPattern, FC_FT_FACE, 0, &face) == FcResultMatch) {
412
0
      UnscaledFontFreeType::GetVariationSettingsFromFace(aOutVariations, face);
413
0
    }
414
0
  }
415
0
416
0
  return true;
417
0
}
418
419
static cairo_user_data_key_t sNativeFontResourceKey;
420
421
static void
422
ReleaseNativeFontResource(void* aData)
423
0
{
424
0
  static_cast<NativeFontResource*>(aData)->Release();
425
0
}
426
427
static cairo_user_data_key_t sFaceKey;
428
429
static void
430
ReleaseFace(void* aData)
431
0
{
432
0
  Factory::ReleaseFTFace(static_cast<FT_Face>(aData));
433
0
}
434
435
already_AddRefed<ScaledFont>
436
UnscaledFontFontconfig::CreateScaledFont(Float aSize,
437
                                         const uint8_t* aInstanceData,
438
                                         uint32_t aInstanceDataLength,
439
                                         const FontVariation* aVariations,
440
                                         uint32_t aNumVariations)
441
0
{
442
0
  if (aInstanceDataLength < sizeof(ScaledFontFontconfig::InstanceData)) {
443
0
    gfxWarning() << "Fontconfig scaled font instance data is truncated.";
444
0
    return nullptr;
445
0
  }
446
0
  const ScaledFontFontconfig::InstanceData& instanceData =
447
0
    *reinterpret_cast<const ScaledFontFontconfig::InstanceData*>(aInstanceData);
448
0
449
0
  FcPattern* pattern = FcPatternCreate();
450
0
  if (!pattern) {
451
0
    gfxWarning() << "Failed initializing Fontconfig pattern for scaled font";
452
0
    return nullptr;
453
0
  }
454
0
  FT_Face face = GetFace();
455
0
  NativeFontResourceFreeType* nfr = static_cast<NativeFontResourceFreeType*>(mNativeFontResource.get());
456
0
  FT_Face varFace = nullptr;
457
0
  if (face) {
458
0
    if (nfr && aNumVariations > 0) {
459
0
      varFace = nfr->CloneFace();
460
0
      if (!varFace) {
461
0
        gfxWarning() << "Failed cloning face for variations";
462
0
      }
463
0
    }
464
0
    FcPatternAddFTFace(pattern, FC_FT_FACE, varFace ? varFace : face);
465
0
  } else {
466
0
    FcPatternAddString(pattern, FC_FILE, reinterpret_cast<const FcChar8*>(GetFile()));
467
0
    FcPatternAddInteger(pattern, FC_INDEX, GetIndex());
468
0
  }
469
0
  FcPatternAddDouble(pattern, FC_PIXEL_SIZE, aSize);
470
0
  instanceData.SetupPattern(pattern);
471
0
472
0
  StackArray<FT_Fixed, 32> coords(aNumVariations);
473
0
  for (uint32_t i = 0; i < aNumVariations; i++) {
474
0
    coords[i] = std::round(aVariations[i].mValue * 65536.0);
475
0
  }
476
0
477
0
  cairo_font_face_t* font = cairo_ft_font_face_create_for_pattern(pattern, coords.data(), aNumVariations);
478
0
  if (cairo_font_face_status(font) != CAIRO_STATUS_SUCCESS) {
479
0
    gfxWarning() << "Failed creating Cairo font face for Fontconfig pattern";
480
0
    FcPatternDestroy(pattern);
481
0
    if (varFace) {
482
0
      Factory::ReleaseFTFace(varFace);
483
0
    }
484
0
    return nullptr;
485
0
  }
486
0
487
0
  if (nfr) {
488
0
    // Bug 1362117 - Cairo may keep the font face alive after the owning NativeFontResource
489
0
    // was freed. To prevent this, we must bind the NativeFontResource to the font face so that
490
0
    // it stays alive at least as long as the font face.
491
0
    nfr->AddRef();
492
0
    cairo_status_t err = CAIRO_STATUS_SUCCESS;
493
0
    bool cleanupFace = false;
494
0
    if (varFace) {
495
0
      err = cairo_font_face_set_user_data(font,
496
0
                                          &sFaceKey,
497
0
                                          varFace,
498
0
                                          ReleaseFace);
499
0
    }
500
0
    if (err != CAIRO_STATUS_SUCCESS) {
501
0
      cleanupFace = true;
502
0
    } else {
503
0
      err = cairo_font_face_set_user_data(font,
504
0
                                          &sNativeFontResourceKey,
505
0
                                          nfr,
506
0
                                          ReleaseNativeFontResource);
507
0
    }
508
0
    if (err != CAIRO_STATUS_SUCCESS) {
509
0
      gfxWarning() << "Failed binding NativeFontResource to Cairo font face";
510
0
      if (varFace && cleanupFace) {
511
0
        Factory::ReleaseFTFace(varFace);
512
0
      }
513
0
      nfr->Release();
514
0
      cairo_font_face_destroy(font);
515
0
      FcPatternDestroy(pattern);
516
0
      return nullptr;
517
0
    }
518
0
  }
519
0
520
0
  cairo_matrix_t sizeMatrix;
521
0
  cairo_matrix_init(&sizeMatrix, aSize, 0, 0, aSize, 0, 0);
522
0
523
0
  cairo_matrix_t identityMatrix;
524
0
  cairo_matrix_init_identity(&identityMatrix);
525
0
526
0
  cairo_font_options_t *fontOptions = cairo_font_options_create();
527
0
  instanceData.SetupFontOptions(fontOptions);
528
0
529
0
  cairo_scaled_font_t* cairoScaledFont =
530
0
    cairo_scaled_font_create(font, &sizeMatrix, &identityMatrix, fontOptions);
531
0
532
0
  cairo_font_options_destroy(fontOptions);
533
0
  cairo_font_face_destroy(font);
534
0
535
0
  if (cairo_scaled_font_status(cairoScaledFont) != CAIRO_STATUS_SUCCESS) {
536
0
    gfxWarning() << "Failed creating Cairo scaled font for font face";
537
0
    FcPatternDestroy(pattern);
538
0
    return nullptr;
539
0
  }
540
0
541
0
  RefPtr<ScaledFontFontconfig> scaledFont =
542
0
    new ScaledFontFontconfig(cairoScaledFont, pattern, this, aSize);
543
0
544
0
  cairo_scaled_font_destroy(cairoScaledFont);
545
0
  FcPatternDestroy(pattern);
546
0
547
0
  // Only apply variations if we have an explicitly cloned face. Otherwise,
548
0
  // if the pattern holds the pathname, Cairo will handle setting of variations.
549
0
  if (varFace) {
550
0
    ApplyVariationsToFace(aVariations, aNumVariations, varFace);
551
0
  }
552
0
553
0
  return scaledFont.forget();
554
0
}
555
556
already_AddRefed<ScaledFont>
557
UnscaledFontFontconfig::CreateScaledFontFromWRFont(Float aGlyphSize,
558
                                                   const wr::FontInstanceOptions* aOptions,
559
                                                   const wr::FontInstancePlatformOptions* aPlatformOptions,
560
                                                   const FontVariation* aVariations,
561
                                                   uint32_t aNumVariations)
562
0
{
563
0
  ScaledFontFontconfig::InstanceData instanceData(aOptions, aPlatformOptions);
564
0
  return CreateScaledFont(aGlyphSize,
565
0
                          reinterpret_cast<uint8_t*>(&instanceData),
566
0
                          sizeof(instanceData),
567
0
                          aVariations, aNumVariations);
568
0
}
569
570
bool
571
ScaledFontFontconfig::HasVariationSettings()
572
0
{
573
0
  // Check if the FT face has been cloned.
574
0
  FT_Face face = nullptr;
575
0
  return FcPatternGetFTFace(mPattern, FC_FT_FACE, 0, &face) == FcResultMatch &&
576
0
         face && face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS &&
577
0
         face != static_cast<UnscaledFontFontconfig*>(mUnscaledFont.get())->GetFace();
578
0
}
579
580
already_AddRefed<UnscaledFont>
581
UnscaledFontFontconfig::CreateFromFontDescriptor(const uint8_t* aData, uint32_t aDataLength, uint32_t aIndex)
582
0
{
583
0
  if (aDataLength == 0) {
584
0
    gfxWarning() << "Fontconfig font descriptor is truncated.";
585
0
    return nullptr;
586
0
  }
587
0
  const char* path = reinterpret_cast<const char*>(aData);
588
0
  RefPtr<UnscaledFont> unscaledFont = new UnscaledFontFontconfig(std::string(path, aDataLength), aIndex);
589
0
  return unscaledFont.forget();
590
0
}
591
592
} // namespace gfx
593
} // namespace mozilla