QtBase  v6.3.1
hb-ot-color-sbix-table.hh
Go to the documentation of this file.
1 /*
2  * Copyright © 2018 Ebrahim Byagowi
3  * Copyright © 2020 Google, Inc.
4  *
5  * This is part of HarfBuzz, a text shaping library.
6  *
7  * Permission is hereby granted, without written agreement and without
8  * license or royalty fees, to use, copy, modify, and distribute this
9  * software and its documentation for any purpose, provided that the
10  * above copyright notice and the following two paragraphs appear in
11  * all copies of this software.
12  *
13  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17  * DAMAGE.
18  *
19  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24  *
25  * Google Author(s): Calder Kitagawa
26  */
27 
28 #ifndef HB_OT_COLOR_SBIX_TABLE_HH
29 #define HB_OT_COLOR_SBIX_TABLE_HH
30 
31 #include "hb-open-type.hh"
32 #include "hb-ot-layout-common.hh"
33 
34 /*
35  * sbix -- Standard Bitmap Graphics
36  * https://docs.microsoft.com/en-us/typography/opentype/spec/sbix
37  * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6sbix.html
38  */
39 #define HB_OT_TAG_sbix HB_TAG('s','b','i','x')
40 
41 
42 namespace OT {
43 
44 
45 struct SBIXGlyph
46 {
47  SBIXGlyph* copy (hb_serialize_context_t *c, unsigned int data_length) const
48  {
49  TRACE_SERIALIZE (this);
50  SBIXGlyph* new_glyph = c->start_embed<SBIXGlyph> ();
51  if (unlikely (!new_glyph)) return_trace (nullptr);
52  if (unlikely (!c->extend_min (new_glyph))) return_trace (nullptr);
53 
54  new_glyph->xOffset = xOffset;
55  new_glyph->yOffset = yOffset;
56  new_glyph->graphicType = graphicType;
57  data.copy (c, data_length);
58  return_trace (new_glyph);
59  }
60 
61  HBINT16 xOffset; /* The horizontal (x-axis) offset from the left
62  * edge of the graphic to the glyph’s origin.
63  * That is, the x-coordinate of the point on the
64  * baseline at the left edge of the glyph. */
65  HBINT16 yOffset; /* The vertical (y-axis) offset from the bottom
66  * edge of the graphic to the glyph’s origin.
67  * That is, the y-coordinate of the point on the
68  * baseline at the left edge of the glyph. */
69  Tag graphicType; /* Indicates the format of the embedded graphic
70  * data: one of 'jpg ', 'png ' or 'tiff', or the
71  * special format 'dupe'. */
73  data; /* The actual embedded graphic data. The total
74  * length is inferred from sequential entries in
75  * the glyphDataOffsets array and the fixed size
76  * (8 bytes) of the preceding fields. */
77  public:
79 };
80 
81 struct SBIXStrike
82 {
83  static unsigned int get_size (unsigned num_glyphs)
84  { return min_size + num_glyphs * HBUINT32::static_size; }
85 
87  {
88  TRACE_SANITIZE (this);
89  return_trace (c->check_struct (this) &&
90  imageOffsetsZ.sanitize_shallow (c, c->get_num_glyphs () + 1));
91  }
92 
93  hb_blob_t *get_glyph_blob (unsigned int glyph_id,
94  hb_blob_t *sbix_blob,
95  hb_tag_t file_type,
96  int *x_offset,
97  int *y_offset,
98  unsigned int num_glyphs,
99  unsigned int *strike_ppem) const
100  {
101  if (unlikely (!ppem)) return hb_blob_get_empty (); /* To get Null() object out of the way. */
102 
103  unsigned int retry_count = 8;
104  unsigned int sbix_len = sbix_blob->length;
105  unsigned int strike_offset = (const char *) this - (const char *) sbix_blob->data;
106  assert (strike_offset < sbix_len);
107 
108  retry:
109  if (unlikely (glyph_id >= num_glyphs ||
110  imageOffsetsZ[glyph_id + 1] <= imageOffsetsZ[glyph_id] ||
111  imageOffsetsZ[glyph_id + 1] - imageOffsetsZ[glyph_id] <= SBIXGlyph::min_size ||
112  (unsigned int) imageOffsetsZ[glyph_id + 1] > sbix_len - strike_offset))
113  return hb_blob_get_empty ();
114 
115  unsigned int glyph_offset = strike_offset + (unsigned int) imageOffsetsZ[glyph_id] + SBIXGlyph::min_size;
116  unsigned int glyph_length = imageOffsetsZ[glyph_id + 1] - imageOffsetsZ[glyph_id] - SBIXGlyph::min_size;
117 
118  const SBIXGlyph *glyph = &(this+imageOffsetsZ[glyph_id]);
119 
120  if (glyph->graphicType == HB_TAG ('d','u','p','e'))
121  {
122  if (glyph_length >= 2)
123  {
124  glyph_id = *((HBUINT16 *) &glyph->data);
125  if (retry_count--)
126  goto retry;
127  }
128  return hb_blob_get_empty ();
129  }
130 
131  if (unlikely (file_type != glyph->graphicType))
132  return hb_blob_get_empty ();
133 
134  if (strike_ppem) *strike_ppem = ppem;
135  if (x_offset) *x_offset = glyph->xOffset;
136  if (y_offset) *y_offset = glyph->yOffset;
137  return hb_blob_create_sub_blob (sbix_blob, glyph_offset, glyph_length);
138  }
139 
140  bool subset (hb_subset_context_t *c, unsigned int available_len) const
141  {
142  TRACE_SUBSET (this);
143  unsigned int num_output_glyphs = c->plan->num_output_glyphs ();
144 
145  auto* out = c->serializer->start_embed<SBIXStrike> ();
146  if (unlikely (!out)) return_trace (false);
147  auto snap = c->serializer->snapshot ();
148  if (unlikely (!c->serializer->extend (out, num_output_glyphs + 1))) return_trace (false);
149  out->ppem = ppem;
150  out->resolution = resolution;
151  HBUINT32 head;
152  head = get_size (num_output_glyphs + 1);
153 
154  bool has_glyphs = false;
155  for (unsigned new_gid = 0; new_gid < num_output_glyphs; new_gid++)
156  {
157  hb_codepoint_t old_gid;
158  if (!c->plan->old_gid_for_new_gid (new_gid, &old_gid) ||
159  unlikely (imageOffsetsZ[old_gid].is_null () ||
160  imageOffsetsZ[old_gid + 1].is_null () ||
161  imageOffsetsZ[old_gid + 1] <= imageOffsetsZ[old_gid] ||
162  imageOffsetsZ[old_gid + 1] - imageOffsetsZ[old_gid] <= SBIXGlyph::min_size) ||
163  (unsigned int) imageOffsetsZ[old_gid + 1] > available_len)
164  {
165  out->imageOffsetsZ[new_gid] = head;
166  continue;
167  }
168  has_glyphs = true;
169  unsigned int delta = imageOffsetsZ[old_gid + 1] - imageOffsetsZ[old_gid];
170  unsigned int glyph_data_length = delta - SBIXGlyph::min_size;
171  if (!(this+imageOffsetsZ[old_gid]).copy (c->serializer, glyph_data_length))
172  return_trace (false);
173  out->imageOffsetsZ[new_gid] = head;
174  head += delta;
175  }
176  if (has_glyphs)
177  out->imageOffsetsZ[num_output_glyphs] = head;
178  else
179  c->serializer->revert (snap);
180  return_trace (has_glyphs);
181  }
182 
183  public:
184  HBUINT16 ppem; /* The PPEM size for which this strike was designed. */
185  HBUINT16 resolution; /* The device pixel density (in PPI) for which this
186  * strike was designed. (E.g., 96 PPI, 192 PPI.) */
187  protected:
189  imageOffsetsZ; /* Offset from the beginning of the strike data header
190  * to bitmap data for an individual glyph ID. */
191  public:
193 };
194 
195 struct sbix
196 {
197  static constexpr hb_tag_t tableTag = HB_OT_TAG_sbix;
198 
199  bool has_data () const { return version; }
200 
201  const SBIXStrike &get_strike (unsigned int i) const { return this+strikes[i]; }
202 
204  {
206  {
207  table = hb_sanitize_context_t ().reference_table<sbix> (face);
208  num_glyphs = face->get_num_glyphs ();
209  }
210  ~accelerator_t () { table.destroy (); }
211 
212  bool has_data () const { return table->has_data (); }
213 
215  hb_codepoint_t glyph,
216  hb_glyph_extents_t *extents) const
217  {
218  /* We only support PNG right now, and following function checks type. */
219  return get_png_extents (font, glyph, extents);
220  }
221 
223  hb_codepoint_t glyph_id,
224  int *x_offset,
225  int *y_offset,
226  unsigned int *available_ppem) const
227  {
228  return choose_strike (font).get_glyph_blob (glyph_id, table.get_blob (),
229  HB_TAG ('p','n','g',' '),
230  x_offset, y_offset,
231  num_glyphs, available_ppem);
232  }
233 
234  private:
235 
236  const SBIXStrike &choose_strike (hb_font_t *font) const
237  {
238  unsigned count = table->strikes.len;
239  if (unlikely (!count))
240  return Null (SBIXStrike);
241 
242  unsigned int requested_ppem = hb_max (font->x_ppem, font->y_ppem);
243  if (!requested_ppem)
244  requested_ppem = 1<<30; /* Choose largest strike. */
245  /* TODO Add DPI sensitivity as well? */
246  unsigned int best_i = 0;
247  unsigned int best_ppem = table->get_strike (0).ppem;
248 
249  for (unsigned int i = 1; i < count; i++)
250  {
251  unsigned int ppem = (table->get_strike (i)).ppem;
252  if ((requested_ppem <= ppem && ppem < best_ppem) ||
253  (requested_ppem > best_ppem && ppem > best_ppem))
254  {
255  best_i = i;
256  best_ppem = ppem;
257  }
258  }
259 
260  return table->get_strike (best_i);
261  }
262 
263  struct PNGHeader
264  {
265  HBUINT8 signature[8];
266  struct
267  {
268  struct
269  {
271  Tag type;
272  } header;
273  HBUINT32 width;
275  HBUINT8 bitDepth;
276  HBUINT8 colorType;
277  HBUINT8 compressionMethod;
278  HBUINT8 filterMethod;
279  HBUINT8 interlaceMethod;
280  } IHDR;
281 
282  public:
283  DEFINE_SIZE_STATIC (29);
284  };
285 
286  bool get_png_extents (hb_font_t *font,
287  hb_codepoint_t glyph,
288  hb_glyph_extents_t *extents) const
289  {
290  /* Following code is safe to call even without data.
291  * But faster to short-circuit. */
292  if (!has_data ())
293  return false;
294 
295  int x_offset = 0, y_offset = 0;
296  unsigned int strike_ppem = 0;
297  hb_blob_t *blob = reference_png (font, glyph, &x_offset, &y_offset, &strike_ppem);
298 
299  const PNGHeader &png = *blob->as<PNGHeader>();
300 
301  extents->x_bearing = x_offset;
302  extents->y_bearing = png.IHDR.height + y_offset;
303  extents->width = png.IHDR.width;
304  extents->height = -1 * png.IHDR.height;
305 
306  /* Convert to font units. */
307  if (strike_ppem)
308  {
309  float scale = font->face->get_upem () / (float) strike_ppem;
310  extents->x_bearing = font->em_scalef_x (extents->x_bearing * scale);
311  extents->y_bearing = font->em_scalef_y (extents->y_bearing * scale);
312  extents->width = font->em_scalef_x (extents->width * scale);
313  extents->height = font->em_scalef_y (extents->height * scale);
314  }
315  else
316  {
317  extents->x_bearing = font->em_scale_x (extents->x_bearing);
318  extents->y_bearing = font->em_scale_y (extents->y_bearing);
319  extents->width = font->em_scale_x (extents->width);
320  extents->height = font->em_scale_y (extents->height);
321  }
322 
323  hb_blob_destroy (blob);
324 
325  return strike_ppem;
326  }
327 
328  private:
330 
331  unsigned int num_glyphs;
332  };
333 
335  {
336  TRACE_SANITIZE (this);
337  return_trace (likely (c->check_struct (this) &&
338  version >= 1 &&
339  strikes.sanitize (c, this)));
340  }
341 
342  bool
343  add_strike (hb_subset_context_t *c, unsigned i) const
344  {
345  if (strikes[i].is_null () || c->source_blob->length < (unsigned) strikes[i])
346  return false;
347 
348  return (this+strikes[i]).subset (c, c->source_blob->length - (unsigned) strikes[i]);
349  }
350 
352  {
353  TRACE_SERIALIZE (this);
354 
355  auto *out = c->serializer->start_embed<Array32OfOffset32To<SBIXStrike>> ();
356  if (unlikely (!out)) return_trace (false);
357  if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
358 
361  for (int i = strikes.len - 1; i >= 0; --i)
362  {
363  auto* o = out->serialize_append (c->serializer);
364  if (unlikely (!o)) return_trace (false);
365  *o = 0;
366  auto snap = c->serializer->snapshot ();
367  c->serializer->push ();
368  bool ret = add_strike (c, i);
369  if (!ret)
370  {
371  c->serializer->pop_discard ();
372  out->pop ();
373  c->serializer->revert (snap);
374  }
375  else
376  {
377  objidxs.push (c->serializer->pop_pack ());
378  new_strikes.push (o);
379  }
380  }
381  for (unsigned int i = 0; i < new_strikes.length; ++i)
382  c->serializer->add_link (*new_strikes[i], objidxs[new_strikes.length - 1 - i]);
383 
384  return_trace (true);
385  }
386 
388  {
389  TRACE_SUBSET (this);
390 
391  sbix *sbix_prime = c->serializer->start_embed<sbix> ();
392  if (unlikely (!sbix_prime)) return_trace (false);
393  if (unlikely (!c->serializer->embed (this->version))) return_trace (false);
394  if (unlikely (!c->serializer->embed (this->flags))) return_trace (false);
395 
397  }
398 
399  protected:
400  HBUINT16 version; /* Table version number — set to 1 */
401  HBUINT16 flags; /* Bit 0: Set to 1. Bit 1: Draw outlines.
402  * Bits 2 to 15: reserved (set to 0). */
404  strikes; /* Offsets from the beginning of the 'sbix'
405  * table to data for each individual bitmap strike. */
406  public:
408 };
409 
412 };
413 
414 
415 } /* namespace OT */
416 
417 #endif /* HB_OT_COLOR_SBIX_TABLE_HH */
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
int width
the width of the widget excluding any window frame
Definition: qwidget.h:148
int height
the height of the widget excluding any window frame
Definition: qwidget.h:149
#define this
Definition: dialogs.cpp:56
hb_blob_t * hb_blob_get_empty()
Definition: hb-blob.cc:226
hb_blob_t * hb_blob_create_sub_blob(hb_blob_t *parent, unsigned int offset, unsigned int length)
Definition: hb-blob.cc:169
void hb_blob_destroy(hb_blob_t *blob)
Definition: hb-blob.cc:262
#define TRACE_SERIALIZE(this)
Definition: hb-debug.hh:426
#define TRACE_SANITIZE(this)
Definition: hb-debug.hh:414
#define return_trace(RET)
Definition: hb-debug.hh:349
#define TRACE_SUBSET(this)
Definition: hb-debug.hh:438
#define DEFINE_SIZE_STATIC(size)
#define HB_OT_TAG_sbix
#define likely(expr)
Definition: hb.hh:250
#define unlikely(expr)
Definition: hb.hh:251
IntType< uint8_t > HBUINT8
IntType< uint32_t > HBUINT32
#define assert
Definition: qcborcommon_p.h:63
GLenum GLuint GLenum GLsizei length
Definition: qopengl.h:270
GLenum type
Definition: qopengl.h:270
GLint GLsizei GLsizei height
GLenum GLenum GLsizei count
GLenum face
GLint GLsizei width
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
const GLubyte * c
Definition: qopenglext.h:12701
GLenum GLenum GLenum GLenum GLenum scale
Definition: qopenglext.h:10817
GLenum GLenum GLsizei void * table
Definition: qopenglext.h:2745
uint32_t hb_codepoint_t
Definition: hb-common.h:106
#define HB_TAG(c1, c2, c3, c4)
Definition: hb-common.h:169
uint32_t hb_tag_t
Definition: hb-common.h:157
QTextStream out(stdout)
[7]
Images * png
[0]
QHttpRequestHeader header("GET", QUrl::toPercentEncoding("/index.html"))
[1]
Definition: hb-null.hh:93
SBIXGlyph * copy(hb_serialize_context_t *c, unsigned int data_length) const
DEFINE_SIZE_ARRAY(8, data)
UnsizedArrayOf< HBUINT8 > data
bool subset(hb_subset_context_t *c, unsigned int available_len) const
static unsigned int get_size(unsigned num_glyphs)
UnsizedArrayOf< Offset32To< SBIXGlyph > > imageOffsetsZ
hb_blob_t * get_glyph_blob(unsigned int glyph_id, hb_blob_t *sbix_blob, hb_tag_t file_type, int *x_offset, int *y_offset, unsigned int num_glyphs, unsigned int *strike_ppem) const
bool sanitize(hb_sanitize_context_t *c) const
DEFINE_SIZE_ARRAY(4, imageOffsetsZ)
bool get_extents(hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
hb_blob_t * reference_png(hb_font_t *font, hb_codepoint_t glyph_id, int *x_offset, int *y_offset, unsigned int *available_ppem) const
bool has_data() const
static constexpr hb_tag_t tableTag
bool add_strike(hb_subset_context_t *c, unsigned i) const
bool sanitize(hb_sanitize_context_t *c) const
DEFINE_SIZE_ARRAY(8, strikes)
Array32OfOffset32To< SBIXStrike > strikes
const SBIXStrike & get_strike(unsigned int i) const
bool subset(hb_subset_context_t *c) const
bool serialize_strike_offsets(hb_subset_context_t *c) const
Definition: data.cpp:95
const Type * as() const
Definition: hb-blob.hh:59
unsigned int length
Definition: hb-blob.hh:65
const char * data
Definition: hb-blob.hh:64
hb_position_t x_bearing
Definition: hb-font.h:141
hb_position_t y_bearing
Definition: hb-font.h:142
hb_position_t height
Definition: hb-font.h:144
hb_position_t width
Definition: hb-font.h:143
Type * push()
Definition: hb-vector.hh:183
unsigned int length
Definition: hb-vector.hh:76
const char * signature