blob: 89ebaa5148db19e2ca4f3e1754f94b9d032d7b9e [file] [log] [blame]
/*
* 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 "platform/fonts/opentype/OpenTypeVerticalData.h"
#include "SkTypeface.h"
#include "platform/SharedBuffer.h"
#include "platform/fonts/SimpleFontData.h"
#include "platform/fonts/GlyphPage.h"
#include "platform/fonts/opentype/OpenTypeTypes.h"
#include "platform/geometry/FloatRect.h"
#include "wtf/RefPtr.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 HheaTag = OT_MAKE_TAG('h', 'h', 'e', 'a');
const SkFontTableTag HmtxTag = OT_MAKE_TAG('h', 'm', 't', 'x');
const SkFontTableTag VheaTag = OT_MAKE_TAG('v', 'h', 'e', 'a');
const SkFontTableTag VmtxTag = OT_MAKE_TAG('v', 'm', 't', 'x');
const SkFontTableTag VORGTag = 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 lineGap;
OpenType::Int16 advanceWidthMax;
OpenType::Int16 minLeftSideBearing;
OpenType::Int16 minRightSideBearing;
OpenType::Int16 xMaxExtent;
OpenType::Int16 caretSlopeRise;
OpenType::Int16 caretSlopeRun;
OpenType::Int16 caretOffset;
OpenType::Int16 reserved[4];
OpenType::Int16 metricDataFormat;
OpenType::UInt16 numberOfHMetrics;
};
struct VheaTable {
DISALLOW_NEW();
OpenType::Fixed version;
OpenType::Int16 ascent;
OpenType::Int16 descent;
OpenType::Int16 lineGap;
OpenType::Int16 advanceHeightMax;
OpenType::Int16 minTopSideBearing;
OpenType::Int16 minBottomSideBearing;
OpenType::Int16 yMaxExtent;
OpenType::Int16 caretSlopeRise;
OpenType::Int16 caretSlopeRun;
OpenType::Int16 caretOffset;
OpenType::Int16 reserved[4];
OpenType::Int16 metricDataFormat;
OpenType::UInt16 numOfLongVerMetrics;
};
struct HmtxTable {
DISALLOW_NEW();
struct Entry {
DISALLOW_NEW();
OpenType::UInt16 advanceWidth;
OpenType::Int16 lsb;
} entries[1];
};
struct VmtxTable {
DISALLOW_NEW();
struct Entry {
DISALLOW_NEW();
OpenType::UInt16 advanceHeight;
OpenType::Int16 topSideBearing;
} entries[1];
};
struct VORGTable {
DISALLOW_NEW();
OpenType::UInt16 majorVersion;
OpenType::UInt16 minorVersion;
OpenType::Int16 defaultVertOriginY;
OpenType::UInt16 numVertOriginYMetrics;
struct VertOriginYMetrics {
DISALLOW_NEW();
OpenType::UInt16 glyphIndex;
OpenType::Int16 vertOriginY;
} vertOriginYMetrics[1];
size_t requiredSize() const {
return sizeof(*this) +
sizeof(VertOriginYMetrics) * (numVertOriginYMetrics - 1);
}
};
#pragma pack()
} // namespace OpenType
OpenTypeVerticalData::OpenTypeVerticalData(const FontPlatformData& platformData)
: m_defaultVertOriginY(0) {
loadMetrics(platformData);
}
void OpenTypeVerticalData::loadMetrics(const FontPlatformData& platformData) {
// Load hhea and hmtx to get x-component of vertical origins.
// If these tables are missing, it's not an OpenType font.
RefPtr<SharedBuffer> buffer = platformData.openTypeTable(OpenType::HheaTag);
const OpenType::HheaTable* hhea =
OpenType::validateTable<OpenType::HheaTable>(buffer);
if (!hhea)
return;
uint16_t countHmtxEntries = hhea->numberOfHMetrics;
if (!countHmtxEntries) {
DLOG(ERROR) << "Invalid numberOfHMetrics";
return;
}
buffer = platformData.openTypeTable(OpenType::HmtxTag);
const OpenType::HmtxTable* hmtx =
OpenType::validateTable<OpenType::HmtxTable>(buffer, countHmtxEntries);
if (!hmtx) {
DLOG(ERROR) << "hhea exists but hmtx does not (or broken)";
return;
}
m_advanceWidths.resize(countHmtxEntries);
for (uint16_t i = 0; i < countHmtxEntries; ++i)
m_advanceWidths[i] = hmtx->entries[i].advanceWidth;
// Load vhea first. This table is required for fonts that support vertical
// flow.
buffer = platformData.openTypeTable(OpenType::VheaTag);
const OpenType::VheaTable* vhea =
OpenType::validateTable<OpenType::VheaTable>(buffer);
if (!vhea)
return;
uint16_t countVmtxEntries = vhea->numOfLongVerMetrics;
if (!countVmtxEntries) {
DLOG(ERROR) << "Invalid numOfLongVerMetrics";
return;
}
// Load VORG. This table is optional.
buffer = platformData.openTypeTable(OpenType::VORGTag);
const OpenType::VORGTable* vorg =
OpenType::validateTable<OpenType::VORGTable>(buffer);
if (vorg && buffer->size() >= vorg->requiredSize()) {
m_defaultVertOriginY = vorg->defaultVertOriginY;
uint16_t countVertOriginYMetrics = vorg->numVertOriginYMetrics;
if (!countVertOriginYMetrics) {
// Add one entry so that hasVORG() becomes true
m_vertOriginY.set(0, m_defaultVertOriginY);
} else {
for (uint16_t i = 0; i < countVertOriginYMetrics; ++i) {
const OpenType::VORGTable::VertOriginYMetrics& metrics =
vorg->vertOriginYMetrics[i];
m_vertOriginY.set(metrics.glyphIndex, metrics.vertOriginY);
}
}
}
// Load vmtx then. This table is required for fonts that support vertical
// flow.
buffer = platformData.openTypeTable(OpenType::VmtxTag);
const OpenType::VmtxTable* vmtx =
OpenType::validateTable<OpenType::VmtxTable>(buffer, countVmtxEntries);
if (!vmtx) {
DLOG(ERROR) << "vhea exists but vmtx does not (or broken)";
return;
}
m_advanceHeights.resize(countVmtxEntries);
for (uint16_t i = 0; i < countVmtxEntries; ++i)
m_advanceHeights[i] = vmtx->entries[i].advanceHeight;
// 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 sizeExtra =
buffer->size() - sizeof(OpenType::VmtxTable::Entry) * countVmtxEntries;
if (sizeExtra % sizeof(OpenType::Int16)) {
DLOG(ERROR) << "vmtx has incorrect tsb count";
return;
}
size_t countTopSideBearings =
countVmtxEntries + sizeExtra / sizeof(OpenType::Int16);
m_topSideBearings.resize(countTopSideBearings);
size_t i;
for (i = 0; i < countVmtxEntries; ++i)
m_topSideBearings[i] = vmtx->entries[i].topSideBearing;
if (i < countTopSideBearings) {
const OpenType::Int16* pTopSideBearingsExtra =
reinterpret_cast<const OpenType::Int16*>(
&vmtx->entries[countVmtxEntries]);
for (; i < countTopSideBearings; ++i, ++pTopSideBearingsExtra)
m_topSideBearings[i] = *pTopSideBearingsExtra;
}
}
float OpenTypeVerticalData::advanceHeight(const SimpleFontData* font,
Glyph glyph) const {
size_t countHeights = m_advanceHeights.size();
if (countHeights) {
uint16_t advanceFUnit =
m_advanceHeights[glyph < countHeights ? glyph : countHeights - 1];
float advance = advanceFUnit * font->sizePerUnit();
return advance;
}
// No vertical info in the font file; use height as advance.
return font->getFontMetrics().height();
}
void OpenTypeVerticalData::getVerticalTranslationsForGlyphs(
const SimpleFontData* font,
const Glyph* glyphs,
size_t count,
float* outXYArray) const {
size_t countWidths = m_advanceWidths.size();
ASSERT(countWidths > 0);
const FontMetrics& metrics = font->getFontMetrics();
float sizePerUnit = font->sizePerUnit();
float ascent = metrics.ascent();
bool useVORG = hasVORG();
size_t countTopSideBearings = m_topSideBearings.size();
float defaultVertOriginY = std::numeric_limits<float>::quiet_NaN();
for (float *end = &(outXYArray[count * 2]); outXYArray != end;
++glyphs, outXYArray += 2) {
Glyph glyph = *glyphs;
uint16_t widthFUnit =
m_advanceWidths[glyph < countWidths ? glyph : countWidths - 1];
float width = widthFUnit * sizePerUnit;
outXYArray[0] = -width / 2;
// For Y, try VORG first.
if (useVORG) {
if (glyph) {
int16_t vertOriginYFUnit = m_vertOriginY.get(glyph);
if (vertOriginYFUnit) {
outXYArray[1] = -vertOriginYFUnit * sizePerUnit;
continue;
}
}
if (std::isnan(defaultVertOriginY))
defaultVertOriginY = -m_defaultVertOriginY * sizePerUnit;
outXYArray[1] = defaultVertOriginY;
continue;
}
// If no VORG, try vmtx next.
if (countTopSideBearings) {
int16_t topSideBearingFUnit =
m_topSideBearings[glyph < countTopSideBearings
? glyph
: countTopSideBearings - 1];
float topSideBearing = topSideBearingFUnit * sizePerUnit;
FloatRect bounds = font->boundsForGlyph(glyph);
outXYArray[1] = bounds.y() - topSideBearing;
continue;
}
// No vertical info in the font file; use ascent as vertical origin.
outXYArray[1] = -ascent;
}
}
} // namespace blink