blob: cbcf6f5f22f22ef17f00e8106f3cce7c675a0baa [file] [log] [blame]
/*
* Copyright © 2018 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Garret Rieger
*/
#ifndef HB_OT_HDMX_TABLE_HH
#define HB_OT_HDMX_TABLE_HH
#include "hb-open-type.hh"
/*
* hdmx -- Horizontal Device Metrics
* https://docs.microsoft.com/en-us/typography/opentype/spec/hdmx
*/
#define HB_OT_TAG_hdmx HB_TAG('h','d','m','x')
namespace OT {
struct DeviceRecord
{
static unsigned int get_size (unsigned count)
{ return hb_ceil_to_4 (min_size + count * HBUINT8::static_size); }
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
bool serialize (hb_serialize_context_t *c,
unsigned pixelSize,
Iterator it,
const hb_vector_t<hb_codepoint_pair_t> new_to_old_gid_list,
unsigned num_glyphs)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend (this, num_glyphs))) return_trace (false);
this->pixelSize = pixelSize;
this->maxWidth =
+ it
| hb_reduce (hb_max, 0u);
for (auto &_ : new_to_old_gid_list)
widthsZ[_.first] = *it++;
return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c, unsigned sizeDeviceRecord) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
c->check_range (this, sizeDeviceRecord)));
}
HBUINT8 pixelSize; /* Pixel size for following widths (as ppem). */
HBUINT8 maxWidth; /* Maximum width. */
UnsizedArrayOf<HBUINT8> widthsZ; /* Array of widths (numGlyphs is from the 'maxp' table). */
public:
DEFINE_SIZE_UNBOUNDED (2);
};
struct hdmx
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_hdmx;
unsigned int get_size () const
{ return min_size + numRecords * sizeDeviceRecord; }
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
bool serialize (hb_serialize_context_t *c,
unsigned version,
Iterator it,
const hb_vector_t<hb_codepoint_pair_t> &new_to_old_gid_list,
unsigned num_glyphs)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min ((*this)))) return_trace (false);
this->version = version;
this->numRecords = it.len ();
this->sizeDeviceRecord = DeviceRecord::get_size (num_glyphs);
for (const hb_item_type<Iterator>& _ : +it)
c->start_embed<DeviceRecord> ()->serialize (c, _.first, _.second, new_to_old_gid_list, num_glyphs);
return_trace (c->successful ());
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *hdmx_prime = c->serializer->start_embed <hdmx> ();
unsigned num_input_glyphs = get_num_glyphs ();
auto it =
+ hb_range ((unsigned) numRecords)
| hb_map ([c, num_input_glyphs, this] (unsigned _)
{
const DeviceRecord *device_record =
&StructAtOffset<DeviceRecord> (&firstDeviceRecord,
_ * sizeDeviceRecord);
auto row =
+ hb_iter (c->plan->new_to_old_gid_list)
| hb_map ([num_input_glyphs, device_record] (hb_codepoint_pair_t _)
{
return device_record->widthsZ.as_array (num_input_glyphs) [_.second];
})
;
return hb_pair ((unsigned) device_record->pixelSize, +row);
})
;
hdmx_prime->serialize (c->serializer, version, it,
c->plan->new_to_old_gid_list,
c->plan->num_output_glyphs ());
return_trace (true);
}
unsigned get_num_glyphs () const
{
return sizeDeviceRecord - DeviceRecord::min_size;
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
!hb_unsigned_mul_overflows (numRecords, sizeDeviceRecord) &&
min_size + numRecords * sizeDeviceRecord > numRecords * sizeDeviceRecord &&
sizeDeviceRecord >= DeviceRecord::min_size &&
c->check_range (this, get_size ()));
}
protected:
HBUINT16 version; /* Table version number (0) */
HBUINT16 numRecords; /* Number of device records. */
HBUINT32 sizeDeviceRecord;
/* Size of a device record, 32-bit aligned. */
DeviceRecord firstDeviceRecord;
/* Array of device records. */
public:
DEFINE_SIZE_MIN (8);
};
} /* namespace OT */
#endif /* HB_OT_HDMX_TABLE_HH */