summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.cc')
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.cc315
1 files changed, 315 insertions, 0 deletions
diff --git a/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.cc b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.cc
new file mode 100644
index 00000000000..6acc43a187d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.cc
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2012 Koji Ishii <kojiishi@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.h"
+
+#include "SkTypeface.h"
+#include "base/memory/scoped_refptr.h"
+#include "third_party/blink/renderer/platform/fonts/opentype/open_type_types.h"
+#include "third_party/blink/renderer/platform/fonts/simple_font_data.h"
+#include "third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.h"
+#include "third_party/blink/renderer/platform/geometry/float_rect.h"
+
+namespace blink {
+namespace OpenType {
+
+// The input characters are big-endian (first is most significant).
+#define OT_MAKE_TAG(ch1, ch2, ch3, ch4) \
+ ((((uint32_t)(ch1)) << 24) | (((uint32_t)(ch2)) << 16) | \
+ (((uint32_t)(ch3)) << 8) | ((uint32_t)(ch4)))
+
+const SkFontTableTag kHheaTag = OT_MAKE_TAG('h', 'h', 'e', 'a');
+const SkFontTableTag kHmtxTag = OT_MAKE_TAG('h', 'm', 't', 'x');
+const SkFontTableTag kVheaTag = OT_MAKE_TAG('v', 'h', 'e', 'a');
+const SkFontTableTag kVmtxTag = OT_MAKE_TAG('v', 'm', 't', 'x');
+const SkFontTableTag kVORGTag = OT_MAKE_TAG('V', 'O', 'R', 'G');
+
+#pragma pack(1)
+
+struct HheaTable {
+ DISALLOW_NEW();
+ OpenType::Fixed version;
+ OpenType::Int16 ascender;
+ OpenType::Int16 descender;
+ OpenType::Int16 line_gap;
+ OpenType::Int16 advance_width_max;
+ OpenType::Int16 min_left_side_bearing;
+ OpenType::Int16 min_right_side_bearing;
+ OpenType::Int16 x_max_extent;
+ OpenType::Int16 caret_slope_rise;
+ OpenType::Int16 caret_slope_run;
+ OpenType::Int16 caret_offset;
+ OpenType::Int16 reserved[4];
+ OpenType::Int16 metric_data_format;
+ OpenType::UInt16 number_of_h_metrics;
+};
+
+struct VheaTable {
+ DISALLOW_NEW();
+ OpenType::Fixed version;
+ OpenType::Int16 ascent;
+ OpenType::Int16 descent;
+ OpenType::Int16 line_gap;
+ OpenType::Int16 advance_height_max;
+ OpenType::Int16 min_top_side_bearing;
+ OpenType::Int16 min_bottom_side_bearing;
+ OpenType::Int16 y_max_extent;
+ OpenType::Int16 caret_slope_rise;
+ OpenType::Int16 caret_slope_run;
+ OpenType::Int16 caret_offset;
+ OpenType::Int16 reserved[4];
+ OpenType::Int16 metric_data_format;
+ OpenType::UInt16 num_of_long_ver_metrics;
+};
+
+struct HmtxTable {
+ DISALLOW_NEW();
+ struct Entry {
+ DISALLOW_NEW();
+ OpenType::UInt16 advance_width;
+ OpenType::Int16 lsb;
+ } entries[1];
+};
+
+struct VmtxTable {
+ DISALLOW_NEW();
+ struct Entry {
+ DISALLOW_NEW();
+ OpenType::UInt16 advance_height;
+ OpenType::Int16 top_side_bearing;
+ } entries[1];
+};
+
+struct VORGTable {
+ DISALLOW_NEW();
+ OpenType::UInt16 major_version;
+ OpenType::UInt16 minor_version;
+ OpenType::Int16 default_vert_origin_y;
+ OpenType::UInt16 num_vert_origin_y_metrics;
+ struct VertOriginYMetrics {
+ DISALLOW_NEW();
+ OpenType::UInt16 glyph_index;
+ OpenType::Int16 vert_origin_y;
+ } vert_origin_y_metrics[1];
+
+ size_t RequiredSize() const {
+ return sizeof(*this) +
+ sizeof(VertOriginYMetrics) * (num_vert_origin_y_metrics - 1);
+ }
+};
+
+#pragma pack()
+
+} // namespace OpenType
+
+OpenTypeVerticalData::OpenTypeVerticalData(sk_sp<SkTypeface> typeface)
+ : default_vert_origin_y_(0),
+ size_per_unit_(0),
+ ascent_fallback_(0),
+ height_fallback_(0) {
+ LoadMetrics(typeface);
+}
+
+static void CopyOpenTypeTable(sk_sp<SkTypeface> typeface,
+ SkFontTableTag tag,
+ Vector<char>& destination) {
+ const size_t table_size = typeface->getTableSize(tag);
+ destination.resize(table_size);
+ if (table_size) {
+ typeface->getTableData(tag, 0, table_size, destination.data());
+ }
+}
+
+void OpenTypeVerticalData::LoadMetrics(sk_sp<SkTypeface> typeface) {
+ // Load hhea and hmtx to get x-component of vertical origins.
+ // If these tables are missing, it's not an OpenType font.
+ Vector<char> buffer;
+ CopyOpenTypeTable(typeface, OpenType::kHheaTag, buffer);
+ const OpenType::HheaTable* hhea =
+ OpenType::ValidateTable<OpenType::HheaTable>(buffer);
+ if (!hhea)
+ return;
+ uint16_t count_hmtx_entries = hhea->number_of_h_metrics;
+ if (!count_hmtx_entries) {
+ DLOG(ERROR) << "Invalid numberOfHMetrics";
+ return;
+ }
+
+ CopyOpenTypeTable(typeface, OpenType::kHmtxTag, buffer);
+ const OpenType::HmtxTable* hmtx =
+ OpenType::ValidateTable<OpenType::HmtxTable>(buffer, count_hmtx_entries);
+ if (!hmtx) {
+ DLOG(ERROR) << "hhea exists but hmtx does not (or broken)";
+ return;
+ }
+ advance_widths_.resize(count_hmtx_entries);
+ for (uint16_t i = 0; i < count_hmtx_entries; ++i)
+ advance_widths_[i] = hmtx->entries[i].advance_width;
+
+ // Load vhea first. This table is required for fonts that support vertical
+ // flow.
+ CopyOpenTypeTable(typeface, OpenType::kVheaTag, buffer);
+ const OpenType::VheaTable* vhea =
+ OpenType::ValidateTable<OpenType::VheaTable>(buffer);
+ if (!vhea)
+ return;
+ uint16_t count_vmtx_entries = vhea->num_of_long_ver_metrics;
+ if (!count_vmtx_entries) {
+ DLOG(ERROR) << "Invalid numOfLongVerMetrics";
+ return;
+ }
+
+ // Load VORG. This table is optional.
+ CopyOpenTypeTable(typeface, OpenType::kVORGTag, buffer);
+ const OpenType::VORGTable* vorg =
+ OpenType::ValidateTable<OpenType::VORGTable>(buffer);
+ if (vorg && buffer.size() >= vorg->RequiredSize()) {
+ default_vert_origin_y_ = vorg->default_vert_origin_y;
+ uint16_t count_vert_origin_y_metrics = vorg->num_vert_origin_y_metrics;
+ if (!count_vert_origin_y_metrics) {
+ // Add one entry so that hasVORG() becomes true
+ vert_origin_y_.Set(0, default_vert_origin_y_);
+ } else {
+ for (uint16_t i = 0; i < count_vert_origin_y_metrics; ++i) {
+ const OpenType::VORGTable::VertOriginYMetrics& metrics =
+ vorg->vert_origin_y_metrics[i];
+ vert_origin_y_.Set(metrics.glyph_index, metrics.vert_origin_y);
+ }
+ }
+ }
+
+ // Load vmtx then. This table is required for fonts that support vertical
+ // flow.
+ CopyOpenTypeTable(typeface, OpenType::kVmtxTag, buffer);
+ const OpenType::VmtxTable* vmtx =
+ OpenType::ValidateTable<OpenType::VmtxTable>(buffer, count_vmtx_entries);
+ if (!vmtx) {
+ DLOG(ERROR) << "vhea exists but vmtx does not (or broken)";
+ return;
+ }
+ advance_heights_.resize(count_vmtx_entries);
+ for (uint16_t i = 0; i < count_vmtx_entries; ++i)
+ advance_heights_[i] = vmtx->entries[i].advance_height;
+
+ // VORG is preferred way to calculate vertical origin than vmtx,
+ // so load topSideBearing from vmtx only if VORG is missing.
+ if (HasVORG())
+ return;
+
+ size_t size_extra =
+ buffer.size() - sizeof(OpenType::VmtxTable::Entry) * count_vmtx_entries;
+ if (size_extra % sizeof(OpenType::Int16)) {
+ DLOG(ERROR) << "vmtx has incorrect tsb count";
+ return;
+ }
+ size_t count_top_side_bearings =
+ count_vmtx_entries + size_extra / sizeof(OpenType::Int16);
+ top_side_bearings_.resize(count_top_side_bearings);
+ size_t i;
+ for (i = 0; i < count_vmtx_entries; ++i)
+ top_side_bearings_[i] = vmtx->entries[i].top_side_bearing;
+ if (i < count_top_side_bearings) {
+ const OpenType::Int16* p_top_side_bearings_extra =
+ reinterpret_cast<const OpenType::Int16*>(
+ &vmtx->entries[count_vmtx_entries]);
+ for (; i < count_top_side_bearings; ++i, ++p_top_side_bearings_extra)
+ top_side_bearings_[i] = *p_top_side_bearings_extra;
+ }
+}
+
+void OpenTypeVerticalData::SetScaleAndFallbackMetrics(float size_per_unit,
+ float ascent,
+ int height) {
+ size_per_unit_ = size_per_unit;
+ ascent_fallback_ = ascent;
+ height_fallback_ = height;
+}
+
+float OpenTypeVerticalData::AdvanceHeight(Glyph glyph) const {
+ size_t count_heights = advance_heights_.size();
+ if (count_heights) {
+ uint16_t advance_f_unit =
+ advance_heights_[glyph < count_heights ? glyph : count_heights - 1];
+ float advance = advance_f_unit * size_per_unit_;
+ return advance;
+ }
+
+ // No vertical info in the font file; use height as advance.
+ return height_fallback_;
+}
+
+void OpenTypeVerticalData::GetVerticalTranslationsForGlyphs(
+ const SkPaint& paint,
+ const Glyph* glyphs,
+ size_t count,
+ float* out_xy_array) const {
+ size_t count_widths = advance_widths_.size();
+ DCHECK_GT(count_widths, 0u);
+ bool use_vorg = HasVORG();
+ size_t count_top_side_bearings = top_side_bearings_.size();
+ float default_vert_origin_y = std::numeric_limits<float>::quiet_NaN();
+ for (float *end = &(out_xy_array[count * 2]); out_xy_array != end;
+ ++glyphs, out_xy_array += 2) {
+ Glyph glyph = *glyphs;
+ uint16_t width_f_unit =
+ advance_widths_[glyph < count_widths ? glyph : count_widths - 1];
+ float width = width_f_unit * size_per_unit_;
+ out_xy_array[0] = -width / 2;
+
+ // For Y, try VORG first.
+ if (use_vorg) {
+ if (glyph) {
+ int16_t vert_origin_yf_unit = vert_origin_y_.at(glyph);
+ if (vert_origin_yf_unit) {
+ out_xy_array[1] = -vert_origin_yf_unit * size_per_unit_;
+ continue;
+ }
+ }
+ if (std::isnan(default_vert_origin_y))
+ default_vert_origin_y = -default_vert_origin_y_ * size_per_unit_;
+ out_xy_array[1] = default_vert_origin_y;
+ continue;
+ }
+
+ // If no VORG, try vmtx next.
+ if (count_top_side_bearings) {
+ int16_t top_side_bearing_f_unit =
+ top_side_bearings_[glyph < count_top_side_bearings
+ ? glyph
+ : count_top_side_bearings - 1];
+ float top_side_bearing = top_side_bearing_f_unit * size_per_unit_;
+
+ SkRect skiaBounds;
+ SkiaTextMetrics(&paint).GetSkiaBoundsForGlyph(glyph, &skiaBounds);
+ FloatRect bounds(skiaBounds);
+ out_xy_array[1] = bounds.Y() - top_side_bearing;
+ continue;
+ }
+
+ // No vertical info in the font file; use ascent as vertical origin.
+ out_xy_array[1] = -ascent_fallback_;
+ }
+}
+
+} // namespace blink