diff options
-rw-r--r-- | skia/SConscript | 1 | ||||
-rw-r--r-- | skia/include/SkPaint.h | 6 | ||||
-rw-r--r-- | skia/ports/SkFontHost_FreeType.cpp | 60 | ||||
-rw-r--r-- | skia/ports/SkFontHost_TrueType_VDMX.cpp | 189 | ||||
-rw-r--r-- | webkit/port/platform/graphics/chromium/SimpleFontDataLinux.cpp | 13 |
5 files changed, 265 insertions, 4 deletions
diff --git a/skia/SConscript b/skia/SConscript index ad1f194..97ea1be 100644 --- a/skia/SConscript +++ b/skia/SConscript @@ -160,6 +160,7 @@ if env['PLATFORM'] == 'posix': input_files.remove('ports/SkFontHost_none.cpp') input_files.append('sgl/SkTypeface.cpp') input_files.append('ports/SkFontHost_FreeType.cpp') + input_files.append('ports/SkFontHost_TrueType_VDMX.cpp') input_files.append('ports/SkFontHost_gamma_none.cpp') input_files.append('ports/SkFontHost_fontconfig.cpp') input_files.append('images/SkMMapStream.cpp') diff --git a/skia/include/SkPaint.h b/skia/include/SkPaint.h index 73e3dbd..06009cb 100644 --- a/skia/include/SkPaint.h +++ b/skia/include/SkPaint.h @@ -587,6 +587,12 @@ public: SkScalar fBottom; //!< The greatest distance below the baseline for any glyph (will be >= 0) SkScalar fLeading; //!< The recommended distance to add between lines of text (will be >= 0) SkScalar fHeight; //!< the vertical distance between two consecutive baselines (>= 0) + + // VDMX values are exact ascent and descent values for scalable fonts at + // a certain pixel size. + bool fVDMXMetricsValid; //!< If true, the following members are valid + unsigned fVDMXAscent; + unsigned fVDMXDescent; }; /** Return the recommend spacing between lines (which will be diff --git a/skia/ports/SkFontHost_FreeType.cpp b/skia/ports/SkFontHost_FreeType.cpp index 2a2444e..172e296 100644 --- a/skia/ports/SkFontHost_FreeType.cpp +++ b/skia/ports/SkFontHost_FreeType.cpp @@ -31,6 +31,7 @@ #include FT_FREETYPE_H #include FT_OUTLINE_H #include FT_SIZES_H +#include FT_TRUETYPE_TABLES_H //#define ENABLE_GLYPH_SPEW // for tracing calls to generateMetrics/generateImage //#define DUMP_STRIKE_CREATION @@ -723,6 +724,51 @@ void SkScalerContext_FreeType::generatePath(const SkGlyph& glyph, SkPath* path) path->close(); } +// ----------------------------------------------------------------------------- +// This is an extern from SkFontHost_TrueType_VDMX. See comments there in for +// details of the arguments. +// ----------------------------------------------------------------------------- +extern bool VDMX_Parse(int* ymax, int* ymin, const uint8_t* vdmx, + const size_t vdmx_length, const unsigned target_pelsize); + +// ----------------------------------------------------------------------------- +// Attempt to load and parse a VDMX table from the given face, extracting a +// ascender and descender values for the given pelsize. +// ymax: (output) the ascender value from the table +// ymin: (output) the descender value from the table (negative!) +// face: A FreeType TrueType or OpenType font +// target_pelsize: the pixel size of the font (e.g. 16) +// +// Returns true iff a suitable match are found. Otherwise, *ymax and *ymin are +// untouched. +// ----------------------------------------------------------------------------- +static bool +SkFontHost_VDMX_Parse(int* ymax, int* ymin, + FT_Face face, unsigned target_pelsize) { + FT_Error error; + + // Request the length of the VDMX table (if any) + FT_ULong vdmx_length = 0; + error = FT_Load_Sfnt_Table(face, FT_MAKE_TAG('V', 'D', 'M', 'X'), + 0, NULL, &vdmx_length); + + if (error || vdmx_length > 1024 * 1024) + return false; + + uint8_t* vdmx = (uint8_t *) malloc(vdmx_length); + error = FT_Load_Sfnt_Table(face, FT_MAKE_TAG('V', 'D', 'M', 'X'), + 0, vdmx, NULL); + if (error) { + free(vdmx); + return false; + } + + bool result = VDMX_Parse(ymax, ymin, vdmx, vdmx_length, target_pelsize); + free(vdmx); + + return result; +} + void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my) { if (NULL == mx && NULL == my) @@ -775,6 +821,10 @@ void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx, SkP mx->fBottom = pts[3].fX; mx->fLeading = pts[4].fX; mx->fHeight = pts[5].fX; + + // The VDMX metrics only make sense in the horizontal direction + // I believe + my->fVDMXMetricsValid = false; } if (my) { @@ -784,6 +834,16 @@ void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx, SkP my->fBottom = pts[3].fY; my->fLeading = pts[4].fY; my->fHeight = pts[5].fY; + my->fVDMXMetricsValid = false; + + // Attempt to parse the VDMX table to get exact metrics + unsigned pelsize = fScaleY >> 16; + int ymax, ymin; + if (SkFontHost_VDMX_Parse(&ymax, &ymin, face, pelsize)) { + my->fVDMXMetricsValid = true; + my->fVDMXAscent = ymax; + my->fVDMXDescent = -ymin; + } } } diff --git a/skia/ports/SkFontHost_TrueType_VDMX.cpp b/skia/ports/SkFontHost_TrueType_VDMX.cpp new file mode 100644 index 0000000..49b4670 --- /dev/null +++ b/skia/ports/SkFontHost_TrueType_VDMX.cpp @@ -0,0 +1,189 @@ +/* libs/graphics/ports/SkFontHost_TrueType_VDMX.cpp +** +** Copyright 2008, Google Inc. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +// ----------------------------------------------------------------------------- +// VDMX parsing code. +// +// VDMX tables are found in some TrueType/OpenType fonts and contain +// ascender/descender overrides for certain (usually small) sizes. This is +// needed in order to match font metrics on Windows. +// +// Freetype does not parse these tables so we do so here. In the future we +// might support loading of arbitary fonts. This is not something that one +// would wish to do, dangerous as it is, so we are careful where we tread. +// ----------------------------------------------------------------------------- + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +// For htons/ntohs +#include <arpa/inet.h> + +// ----------------------------------------------------------------------------- +// Buffer helper class +// +// This class perform some trival buffer operations while checking for +// out-of-bounds errors. As a family they return false if anything is amiss, +// updating the current offset otherwise. +// ----------------------------------------------------------------------------- +class Buffer { + public: + Buffer(const uint8_t* buffer, size_t length) + : buffer_(buffer), + length_(length), + offset_(0) { } + + bool Skip(size_t n_bytes) { + if (offset_ + n_bytes > length_) + return false; + offset_ += n_bytes; + return true; + } + + bool ReadU8(uint8_t* value) { + if (offset_ + 1 > length_) + return false; + *value = buffer_[offset_]; + offset_++; + return true; + } + + bool ReadU16(uint16_t* value) { + if (offset_ + 2 > length_) + return false; + memcpy(value, buffer_ + offset_, sizeof(uint16_t)); + *value = ntohs(*value); + offset_ += 2; + return true; + } + + bool ReadS16(int16_t* value) { + return ReadU16(reinterpret_cast<uint16_t*>(value)); + } + + size_t offset() const { return offset_; } + + void set_offset(size_t newoffset) { offset_ = newoffset; } + + private: + const uint8_t *const buffer_; + const size_t length_; + size_t offset_; +}; + +// ----------------------------------------------------------------------------- +// Parse a TrueType VDMX table. +// ymax: (output) the ascender value from the table +// ymin: (output) the descender value from the table (negative!) +// vdmx: the table bytes +// vdmx_length: length of @vdmx, in bytes +// target_pelsize: the pixel size of the font (e.g. 16) +// +// Returns true iff a suitable match are found. Otherwise, *ymax and *ymin are +// untouched. size_t must be 32-bits to avoid overflow. +// +// See http://www.microsoft.com/opentype/otspec/vdmx.htm +// ----------------------------------------------------------------------------- +bool +VDMX_Parse(int* ymax, int* ymin, + const uint8_t* vdmx, const size_t vdmx_length, + const unsigned target_pelsize) { + Buffer buf(vdmx, vdmx_length); + + // We ignore the version. Future tables should be backwards compatible with + // this layout. + uint16_t numratios; + if (!buf.Skip(4) || + !buf.ReadU16(&numratios)) + return false; + + // Now we have two tables. Firstly we have @numratios Ratio records, then a + // matching array of @numratios offsets. We save the offset of the beginning + // of this second table. + // + // Range 6 <= x <= 262146 + unsigned long offset_table_offset = + buf.offset() + 4 /* sizeof struct ratio */ * numratios; + + unsigned desired_ratio = 0xffffffff; + // We read 4 bytes per record, so the offset range is + // 6 <= x <= 524286 + for (unsigned i = 0; i < numratios; ++i) { + uint8_t xratio, yratio1, yratio2; + + if (!buf.Skip(1) || + !buf.ReadU8(&xratio) || + !buf.ReadU8(&yratio1) || + !buf.ReadU8(&yratio2)) + return false; + + // This either covers 1:1, or this is the default entry (0, 0, 0) + if ((xratio == 1 && yratio1 <= 1 && yratio2 >= 1) || + (xratio == 0 && yratio1 == 0 && yratio2 == 0)) { + desired_ratio = i; + break; + } + } + + if (desired_ratio == 0xffffffff) { + // no ratio found + return false; + } + + // Range 10 <= x <= 393216 + buf.set_offset(offset_table_offset + sizeof(uint16_t) * desired_ratio); + + // Now we read from the offset table to get the offset of another array + uint16_t group_offset; + if (!buf.ReadU16(&group_offset)) + return false; + // Range 0 <= x <= 65535 + buf.set_offset(group_offset); + + uint16_t num_records; + if (!buf.ReadU16(&num_records) || + !buf.Skip(sizeof(uint16_t))) + return false; + + // We read 6 bytes per record, so the offset range is + // 4 <= x <= 458749 + for (unsigned i = 0; i < num_records; ++i) { + uint16_t pel_size; + if (!buf.ReadU16(&pel_size)) + return false; + // the entries are sorted, so we can abort early if need be + if (pel_size > target_pelsize) + return false; + + if (pel_size == target_pelsize) { + int16_t t_ymax, t_ymin; + if (!buf.ReadS16(&t_ymax) || + !buf.ReadS16(&t_ymin)) + return false; + *ymin = t_ymin; + *ymax = t_ymax; + return true; + } else { + if (!buf.Skip(2 * sizeof(int16_t))) + return false; + } + } + + return false; +} diff --git a/webkit/port/platform/graphics/chromium/SimpleFontDataLinux.cpp b/webkit/port/platform/graphics/chromium/SimpleFontDataLinux.cpp index 34fb478..8e0e3f6 100644 --- a/webkit/port/platform/graphics/chromium/SimpleFontDataLinux.cpp +++ b/webkit/port/platform/graphics/chromium/SimpleFontDataLinux.cpp @@ -31,11 +31,16 @@ void SimpleFontData::platformInit() // Beware those who step here: This code is designed to match Win32 font // metrics *exactly*. - m_ascent = SkScalarCeil(-metrics.fAscent); - m_descent = SkScalarCeil(metrics.fHeight) - m_ascent; + if (metrics.fVDMXMetricsValid) { + m_ascent = metrics.fVDMXAscent; + m_descent = metrics.fVDMXDescent; + } else { + m_ascent = SkScalarCeil(-metrics.fAscent); + m_descent = SkScalarCeil(metrics.fHeight) - m_ascent; + } + m_xHeight = SkScalarToFloat(-metrics.fAscent) * 0.56f; // hack I stole from the Windows port - m_lineGap = SkScalarCeil(metrics.fHeight - - (metrics.fDescent - metrics.fAscent)); + m_lineGap = SkScalarRound(metrics.fLeading); m_lineSpacing = m_ascent + m_descent + m_lineGap; // In WebKit/WebCore/platform/graphics/SimpleFontData.cpp, m_spaceWidth is |