blob: e09d7954ffc7eac67f7d5777da31b8fc86a28251 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/**
* @author Dmitriy S. Matveev
*/
#include <stdio.h>
#include "TTFont.h"
#include "Tables.h"
TTFont::TTFont(fchar* pathToFile):Font()
{
_pathToFile=pathToFile;
_glyphOffsets.offsets = NULL;
_tableEncode.TableEncode = NULL;
_famName = NULL;
_ttfile = NULL;
_hMetrics = NULL;
_psName = NULL;
_ttfile = fopen(_pathToFile,"rb");
parseNameTable(_ttfile, &_famName, &_psName, NULL);
parseCmapTable(_ttfile, &_tableEncode);
parseMaxpTable(_ttfile, &_numGlyphs);
parseHeadTable(_ttfile, _boundingBox, &(_glyphOffsets.format), &_unitsPerEm);
for (fint i=0; i<4; i++)
_boundingBox[i]/=(ffloat)(_unitsPerEm);
parseLocaTable(_ttfile, &(_glyphOffsets), _numGlyphs);
parseHheaTable(_ttfile, &_numOfHMetrics, &_ascent, &_descent, &_externalLeading);
_ascent/=(ffloat)(_unitsPerEm);
_descent = ((_descent>0)?_descent:(-_descent))/_unitsPerEm;
_externalLeading/=(ffloat)(_unitsPerEm);
parseHmtxTable(_ttfile, _numOfHMetrics, &_hMetrics);
fclose(_ttfile);
}
TTFont::~TTFont(void)
{
delete[] _glyphOffsets.offsets;
delete[] (fint*)(_tableEncode.TableEncode);
delete[] _psName;
delete[] _hMetrics;
}
Glyph* TTFont::createGlyph(ufshort unicode, ufshort size)
{
TTGlyph *gl = new TTGlyph(this, unicode, size);
if (gl->_index < _numOfHMetrics)
gl->_advanceX = _hMetrics[gl->_index].adwance_width*(ffloat)(size)/(ffloat)(_unitsPerEm);
else
gl->_advanceX = _hMetrics[_numOfHMetrics-1].adwance_width*(ffloat)(size)/(ffloat)(_unitsPerEm);
gl->_advanceY = 0;
return gl;
}
ufshort TTFont::getGlyphIndex(ufshort symb)
{
ufshort index = 0;
if (_tableEncode.format == 0)
{
ufchar* te = (ufchar*)_tableEncode.TableEncode;
index = te[symb];
}else if (_tableEncode.format == 4)
{
ufshort segCountX2;
ufshort segCount;
// ufshort search_range;
// ufshort entry_selector;
// ufshort range_shift;
ufshort* end_count;
ufshort* start_count;
ufshort* idDelta;
ufshort* idRangeOffset;
ufshort reservedPad;
ufshort* te = (ufshort*)(_tableEncode.TableEncode);
fint i;
segCountX2 = te[0];
segCount = segCountX2/2;
end_count = te+4;
reservedPad = te[segCount+4];
start_count = te+segCount+5;
idDelta = te+2*segCount+5;
idRangeOffset = te+3*segCount+5;
for (i=0;i<segCount;i++)
{
if (symb<=end_count[i] && symb>=start_count[i])
{
break;
}
}
if (idRangeOffset[i] != 0)
index = (*(idRangeOffset[i]/2 + (symb - start_count[i]) + &idRangeOffset[i]) + idDelta[i]) % 65536;
else
index = (symb + idDelta[i]) % 65536;
}
return index;
}
ufshort TTFont::getUnicodeByIndex(ufshort ind)
{
ufshort symb = 0;
if (_tableEncode.format == 0)
{
ufchar* te = (ufchar*)_tableEncode.TableEncode;
for (ufshort i = 0; i<=_numGlyphs; i++)
{
if (ind = te[i])
{
symb = i;
break;
}
}
}else
if (_tableEncode.format == 4)
{
ufshort segCountX2;
ufshort segCount;
ufshort* end_count;
ufshort* start_count;
ufshort* idDelta;
ufshort* idRangeOffset;
ufshort reservedPad;
ufshort* te = (ufshort*)(_tableEncode.TableEncode);
fint i;
segCountX2 = te[0];
segCount = segCountX2/2;
end_count = te+4;
reservedPad = te[segCount+4];
start_count = te+segCount+5;
idDelta = te+2*segCount+5;
idRangeOffset = te+3*segCount+5;
for (i=0;i<segCount;i++)
{
if (idRangeOffset[i] != 0)
for (fint j=0; j< _numGlyphs; j++)
{
if (ind - idDelta[i] == idRangeOffset[j] )
symb = (ufshort)(&idRangeOffset[j] - idRangeOffset[i]/2 + start_count[i] - &idRangeOffset[i]);
}
else
symb = (ind - idDelta[i]) % 65536;
if (symb<=end_count[i] && symb>=start_count[i])
{
break;
}
}
}
return symb;
}
fwchar_t* TTFont::getPSName()
{
return _psName;
}
ffloat* TTFont::getLineMetrics()
{
//printf("reading file...\n");
_ttfile = fopen(_pathToFile,"rb");
ffloat* ret = new ffloat[8];
ret[0] = _ascent;
ret[1] = _descent;
ret[2] = _externalLeading;
fshort uOffset, uThickness;
//printf("parsing POST table...\n");
parsePostTable(_ttfile, &uOffset, &uThickness);
ret[3] = (ffloat)uThickness/(ffloat)(_unitsPerEm);
ret[4] = (ffloat)uOffset/(ffloat)(_unitsPerEm);
//printf("parsing OS2 table...\n");
parseOs2Table(_ttfile, &_strikeOutSize, &_strikeOutOffset);
ret[5] = _strikeOutSize;
ret[6] = _strikeOutOffset;
ffloat width = _boundingBox[3]-_boundingBox[1];
ret[7] = (width>0)?width:(-width);
fclose(_ttfile);
return ret;
}
bool TTFont::canDisplay(ufshort c)
{
ufshort index = getGlyphIndex(c);
#ifdef WIN32
bool isComposite = isCompositeGlyph(_ttfile, _glyphOffsets, _numGlyphs, index);
if (index == 0 || index >= _numGlyphs || isComposite)
return false;
#else
if (index == 0 || index >= _numGlyphs)
return false;
#endif
return true;
}
/* *************** */
/* TTGlyph methods */
/* *************** */
TTGlyph::TTGlyph(TTFont* font, ufshort unicode, ufshort size):Glyph()
{
_ttfont = font;
_unicode = unicode;
_size = size;
_curve = new TTCurve();
_boundingRect[0]=0;
_boundingRect[1]=0;
_boundingRect[2]=0;
_boundingRect[3]=0;
_ttfont->_ttfile = fopen(_ttfont->_pathToFile,"rb");
_index = _ttfont->getGlyphIndex(_unicode);
parseGlyphData(_ttfont->_ttfile, _ttfont->_glyphOffsets,_ttfont->_numGlyphs,_index, _curve, _boundingRect, (ffloat)_size/(ffloat)(_ttfont->_unitsPerEm));
fclose(_ttfont->_ttfile);
}
TTGlyph::~TTGlyph()
{
delete _curve;
}
ffloat* TTGlyph::getGlyphMetrics(void){
ffloat* gMetrics = new ffloat[6];
gMetrics[0]=_advanceX;
gMetrics[1]=_advanceY;
gMetrics[2]=_boundingRect[0];
gMetrics[3]=_boundingRect[1];
gMetrics[4]=_boundingRect[2];
gMetrics[5]=_boundingRect[3];
return gMetrics;
}
Outline* TTGlyph::getOutline(void)
{
Outline* outline = new Outline(_curve->_len,_curve->_outlineCommandsNumb);
for (fint i = 0; i<_curve->_len; i+=2)
{
switch(_curve->_flags[i/2])
{
case OPEN_FLAG:
if (i!=0) outline->closePath();
outline->moveTo(_curve->_coords[i],_curve->_coords[i+1]);
break;
case FLAG_ONCURVE:
if (_curve->_flags[i/2-1] & FLAG_ONCURVE || _curve->_flags[i/2-1] & OPEN_FLAG)
outline->lineTo(_curve->_coords[i],_curve->_coords[i+1]);
else
outline->quadTo(_curve->_coords[i-2],_curve->_coords[i-1],_curve->_coords[i],_curve->_coords[i+1]);
}
}
outline->closePath();
return outline;
}