2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
|
|
|
|
#ifndef __LP64__
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
#include <iostream>
|
|
|
|
#include <string>
|
|
|
|
#include "tmathutil.h"
|
|
|
|
#include "tdebugmessage.h"
|
|
|
|
#include "tfont.h"
|
|
|
|
#include "tstroke.h"
|
|
|
|
#include "tcurves.h"
|
|
|
|
#include "tconvert.h"
|
|
|
|
#include "tvectorimage.h"
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
//----------------------------------------- structures
|
|
|
|
//-------------------------------------------------------------------
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
typedef struct {
|
2016-06-15 18:43:10 +12:00
|
|
|
Float32Point origin; // The origin of the current glyph
|
|
|
|
Boolean first; // Keeps track of which segment is first in a glyph
|
|
|
|
Float32Point
|
|
|
|
current; // The current pen position (used to filter degenerate cases)
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
float adv;
|
|
|
|
TVectorImageP m_image;
|
|
|
|
std::vector<TThickPoint> m_points;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
} MyCurveCallbackData;
|
|
|
|
|
|
|
|
typedef struct {
|
2016-06-15 18:43:10 +12:00
|
|
|
ATSGlyphRef glyphID; // The glyphID. This is simply an index into a table in
|
|
|
|
// the font.
|
|
|
|
Float32Point relativeOrigin; // The origin of this glyph -- relative to the
|
|
|
|
// origin of the line.
|
2016-03-19 06:57:51 +13:00
|
|
|
} MyGlyphRecord;
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
//-----------------------------------------
|
|
|
|
//callback---------------------------------------------------------------------
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
OSStatus MyQuadraticLineProc(const Float32Point *pt1, const Float32Point *pt2,
|
|
|
|
void *callBackDataPtr) {
|
|
|
|
/*
|
|
|
|
// Adjust the points according to the glyph origin
|
|
|
|
float x1 = ((MyCurveCallbackData *)callBackDataPtr)->origin.x + pt1->x;
|
|
|
|
float y1 = ((MyCurveCallbackData *)callBackDataPtr)->origin.y + pt1->y;
|
|
|
|
float x2 = ((MyCurveCallbackData *)callBackDataPtr)->origin.x + pt2->x;
|
|
|
|
float y2 = ((MyCurveCallbackData *)callBackDataPtr)->origin.y + pt2->y;
|
|
|
|
*/
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
MyCurveCallbackData *data = (MyCurveCallbackData *)callBackDataPtr;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
if (data->m_points.empty())
|
|
|
|
data->m_points.push_back(TThickPoint(pt1->x, pt1->y, 0));
|
|
|
|
// else
|
|
|
|
// assert(isAlmostEqual(pt1 e back)
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
TThickPoint lastPoint = TThickPoint(pt2->x, pt2->y, 0);
|
|
|
|
data->m_points.push_back((data->m_points.back() + lastPoint) * 0.5);
|
|
|
|
data->m_points.push_back(lastPoint);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
return noErr;
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
OSStatus MyQuadraticCurveProc(const Float32Point *pt1,
|
|
|
|
const Float32Point *controlPt,
|
|
|
|
const Float32Point *pt2, void *callBackDataPtr) {
|
|
|
|
/*
|
|
|
|
// Adjust the points according to the glyph origin
|
|
|
|
float x1 = ((MyCurveCallbackData *)callBackDataPtr)->origin.x + pt1->x;
|
|
|
|
float y1 = ((MyCurveCallbackData *)callBackDataPtr)->origin.y + pt1->y;
|
|
|
|
float x2 = ((MyCurveCallbackData *)callBackDataPtr)->origin.x + pt2->x;
|
|
|
|
float y2 = ((MyCurveCallbackData *)callBackDataPtr)->origin.y + pt2->y;
|
|
|
|
float cpx = ((MyCurveCallbackData *)callBackDataPtr)->origin.x + controlPt->x;
|
|
|
|
float cpy = ((MyCurveCallbackData *)callBackDataPtr)->origin.y + controlPt->y;
|
|
|
|
*/
|
|
|
|
MyCurveCallbackData *data = (MyCurveCallbackData *)callBackDataPtr;
|
|
|
|
|
|
|
|
if (data->m_points.empty())
|
|
|
|
data->m_points.push_back(TThickPoint(pt1->x, pt1->y, 0));
|
|
|
|
// else
|
|
|
|
// assert(isAlmostEqual(pt1 e back)
|
|
|
|
|
|
|
|
data->m_points.push_back(TThickPoint(controlPt->x, controlPt->y, 0));
|
|
|
|
data->m_points.push_back(TThickPoint(pt2->x, pt2->y, 0));
|
|
|
|
|
|
|
|
return noErr;
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
OSStatus MyQuadraticNewPathProc(void *callBackDataPtr) {
|
|
|
|
assert(((MyCurveCallbackData *)callBackDataPtr)->m_points.empty());
|
|
|
|
return noErr;
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
OSStatus MyQuadraticClosePathProc(void *callBackDataPtr) {
|
|
|
|
MyCurveCallbackData *data = (MyCurveCallbackData *)callBackDataPtr;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
assert(
|
|
|
|
data->m_points.size() >= 3 &&
|
|
|
|
data->m_points.size() &
|
|
|
|
1); // il numero di punti di controllo devono essere dispari e >= 3
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
TStroke *stroke = new TStroke(data->m_points);
|
|
|
|
stroke->setSelfLoop(true);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
data->m_points.clear();
|
|
|
|
data->m_image->addStroke(stroke);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
return noErr;
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
void GetGlyphIDsAndPositions(ATSUTextLayout iLayout, UniCharArrayOffset iStart,
|
|
|
|
UniCharCount iLength,
|
|
|
|
MyGlyphRecord **oGlyphRecordArray,
|
|
|
|
ItemCount *oNumGlyphs) {
|
|
|
|
// This block of code uses the new Direct Access APIs, which are only
|
|
|
|
// available on Mac OS X 10.2 and later systems
|
|
|
|
//
|
|
|
|
|
|
|
|
ATSLayoutRecord *layoutRecords;
|
|
|
|
ItemCount numRecords;
|
|
|
|
Fixed *deltaYs;
|
|
|
|
ItemCount numDeltaYs;
|
|
|
|
unsigned int i;
|
|
|
|
OSStatus status;
|
|
|
|
|
|
|
|
// Get the arrays of glyph information
|
|
|
|
status = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(
|
|
|
|
iLayout, iStart, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
|
|
|
|
(void **)&layoutRecords, &numRecords);
|
|
|
|
assert(status == noErr);
|
|
|
|
|
|
|
|
status = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(
|
|
|
|
iLayout, iStart, kATSUDirectDataBaselineDeltaFixedArray,
|
|
|
|
(void **)&deltaYs, &numDeltaYs);
|
|
|
|
assert(status == noErr);
|
|
|
|
|
|
|
|
// Build the array of MyGlyphRecords
|
|
|
|
*oGlyphRecordArray =
|
|
|
|
(MyGlyphRecord *)malloc(numRecords * sizeof(MyGlyphRecord));
|
|
|
|
*oNumGlyphs = numRecords;
|
|
|
|
|
|
|
|
for (i = 0; i < *oNumGlyphs; i++) {
|
|
|
|
// Fill in the glyphID
|
|
|
|
(*oGlyphRecordArray)[i].glyphID = layoutRecords[i].glyphID;
|
|
|
|
|
|
|
|
// Set up the relative origin of the glyph
|
|
|
|
//
|
|
|
|
// The real position is the x coordinate of the glyph, relative to the
|
|
|
|
// beginning of the line
|
|
|
|
// The baseline delta (deltaY), if any, is the y coordinate of the glyph,
|
|
|
|
// relative to the baseline
|
|
|
|
//
|
|
|
|
(*oGlyphRecordArray)[i].relativeOrigin.x = Fix2X(layoutRecords[i].realPos);
|
|
|
|
|
|
|
|
if (deltaYs == NULL) {
|
|
|
|
(*oGlyphRecordArray)[i].relativeOrigin.y = 0.0;
|
|
|
|
} else {
|
|
|
|
(*oGlyphRecordArray)[i].relativeOrigin.y = 0.0 - Fix2X(deltaYs[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Free the arrays of glyph information
|
|
|
|
if (deltaYs != NULL) {
|
|
|
|
status = ATSUDirectReleaseLayoutDataArrayPtr(
|
|
|
|
NULL, kATSUDirectDataBaselineDeltaFixedArray, (void **)&deltaYs);
|
|
|
|
assert(status == noErr);
|
|
|
|
}
|
|
|
|
status = ATSUDirectReleaseLayoutDataArrayPtr(
|
|
|
|
NULL, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
|
|
|
|
(void **)&layoutRecords);
|
|
|
|
assert(status == noErr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void drawQuadratics(ATSUTextLayout iLayout, ATSUStyle iStyle,
|
|
|
|
UniCharArrayOffset start, UniCharCount length,
|
|
|
|
MyCurveCallbackData &data) {
|
|
|
|
// boh ----------------
|
|
|
|
Fixed penX = 0;
|
|
|
|
Fixed penY = 0;
|
|
|
|
// -------------------
|
|
|
|
|
|
|
|
MyGlyphRecord *glyphRecordArray;
|
|
|
|
ItemCount numGlyphs;
|
|
|
|
ATSQuadraticNewPathUPP newPathProc;
|
|
|
|
ATSQuadraticLineUPP lineProc;
|
|
|
|
ATSQuadraticCurveUPP curveProc;
|
|
|
|
ATSQuadraticClosePathUPP closePathProc;
|
|
|
|
|
|
|
|
OSStatus status;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
// Create the Quadratic callbacks
|
|
|
|
newPathProc = NewATSQuadraticNewPathUPP(MyQuadraticNewPathProc);
|
|
|
|
lineProc = NewATSQuadraticLineUPP(MyQuadraticLineProc);
|
|
|
|
curveProc = NewATSQuadraticCurveUPP(MyQuadraticCurveProc);
|
|
|
|
closePathProc = NewATSQuadraticClosePathUPP(MyQuadraticClosePathProc);
|
|
|
|
|
|
|
|
// Get the array of glyph information
|
|
|
|
GetGlyphIDsAndPositions(iLayout, start, length, &glyphRecordArray,
|
|
|
|
&numGlyphs);
|
|
|
|
|
|
|
|
// Loop over all the glyphs
|
|
|
|
for (i = 0; i < numGlyphs; i++) {
|
|
|
|
// Set up the absolute origin of the glyph
|
|
|
|
data.origin.x = Fix2X(penX) + glyphRecordArray[i].relativeOrigin.x;
|
|
|
|
data.origin.y = Fix2X(penY) + glyphRecordArray[i].relativeOrigin.y;
|
|
|
|
|
|
|
|
// Reset state for quadratic drawing (the callbacks only do a MoveTo on the
|
|
|
|
// very first segment)
|
|
|
|
data.first = true;
|
|
|
|
|
|
|
|
// If this is a deleted glyph (-1), don't draw it. Otherwise, go ahead.
|
|
|
|
if (glyphRecordArray[i].glyphID != kATSDeletedGlyphcode) {
|
|
|
|
status = ATSUGlyphGetQuadraticPaths(iStyle, glyphRecordArray[i].glyphID,
|
|
|
|
newPathProc, lineProc, curveProc,
|
|
|
|
closePathProc, &data, &status);
|
|
|
|
assert(status == noErr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Free the array of glyph information
|
|
|
|
free(glyphRecordArray);
|
|
|
|
|
|
|
|
// Dispose of the Quadratic callbacks
|
|
|
|
|
|
|
|
DisposeATSQuadraticNewPathUPP(newPathProc);
|
|
|
|
DisposeATSQuadraticLineUPP(lineProc);
|
|
|
|
DisposeATSQuadraticCurveUPP(curveProc);
|
|
|
|
DisposeATSQuadraticClosePathUPP(closePathProc);
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
|
|
|
|
|
|
struct TFont::Impl {
|
2016-06-15 18:43:10 +12:00
|
|
|
bool m_hasKerning;
|
|
|
|
int m_hasVertical;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
// KerningPairs m_kerningPairs;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
ATSUStyle m_style;
|
|
|
|
ATSUFontID m_fontId;
|
|
|
|
ATSUTextLayout m_layout;
|
|
|
|
Fixed m_size;
|
|
|
|
int m_ascender;
|
|
|
|
int m_descender;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
Impl(ATSUFontID fontId, int size);
|
|
|
|
~Impl();
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
// void getChar();
|
2016-03-19 06:57:51 +13:00
|
|
|
};
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
TFont::TFont(ATSUFontID fontId, int size) { m_pimpl = new Impl(fontId, size); }
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
TFont::~TFont() { delete m_pimpl; }
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
TFont::Impl::Impl(ATSUFontID fontId, int size)
|
2016-06-15 18:43:10 +12:00
|
|
|
: m_fontId(fontId), m_size(Long2Fix(size)) {
|
|
|
|
OSStatus status;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
long response;
|
|
|
|
status = Gestalt(gestaltATSUFeatures, &response);
|
|
|
|
assert(response & gestaltATSUDirectAccess);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
status = ATSUCreateStyle(&m_style);
|
|
|
|
assert(status == noErr);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
ATSUAttributeTag tags[2];
|
|
|
|
ByteCount sizes[2];
|
|
|
|
ATSUAttributeValuePtr values[2];
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
tags[0] = kATSUFontTag;
|
|
|
|
sizes[0] = sizeof(ATSUFontID);
|
|
|
|
values[0] = &fontId;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
tags[1] = kATSUSizeTag;
|
|
|
|
sizes[1] = sizeof(Fixed);
|
|
|
|
values[1] = &m_size;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
status = ATSUSetAttributes(m_style, 2, tags, sizes, values);
|
|
|
|
// assert(status==noErr);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
UniChar dummyStr[] = {'H', 'e', 'l', 'l', 'o'};
|
|
|
|
UniCharCount length = sizeof(dummyStr) / sizeof(UniChar);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
status = ATSUCreateTextLayoutWithTextPtr(dummyStr, kATSUFromTextBeginning,
|
|
|
|
kATSUToTextEnd, length, 1, &length,
|
|
|
|
&m_style, &m_layout);
|
|
|
|
// assert(status==noErr);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
ATSTrapezoid glyphBounds;
|
|
|
|
status =
|
|
|
|
ATSUGetGlyphBounds(m_layout, 0, 0, kATSUFromTextBeginning, kATSUToTextEnd,
|
|
|
|
kATSUseFractionalOrigins, 1, &glyphBounds, NULL);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
m_ascender = -FixedToInt(glyphBounds.upperLeft.y);
|
|
|
|
assert(m_ascender > 0);
|
|
|
|
m_descender = -FixedToInt(glyphBounds.lowerLeft.y);
|
|
|
|
assert(m_descender < 0);
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
TFont::Impl::~Impl() {}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
TPoint TFont::drawChar(TVectorImageP &image, wchar_t charcode,
|
|
|
|
wchar_t nextCharCode) const {
|
|
|
|
OSStatus status;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
UniChar subString[2];
|
|
|
|
subString[0] = charcode;
|
|
|
|
subString[1] = 0 /*nextCharCode*/;
|
|
|
|
UniCharCount length = sizeof(subString) / sizeof(UniChar);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
status = ATSUCreateTextLayoutWithTextPtr(
|
|
|
|
subString, kATSUFromTextBeginning, kATSUToTextEnd, length, 1, &length,
|
|
|
|
&(m_pimpl->m_style), &(m_pimpl->m_layout));
|
|
|
|
assert(status == noErr);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
MyCurveCallbackData data;
|
|
|
|
data.m_image = image;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
drawQuadratics(m_pimpl->m_layout, m_pimpl->m_style, kATSUFromTextBeginning,
|
|
|
|
kATSUToTextEnd, data);
|
|
|
|
image->transform(TScale(1, -1));
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
image->group(0, image->getStrokeCount());
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
return getDistance(charcode, nextCharCode);
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2016-06-15 18:43:10 +12:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
void appDrawChar(TRasterGR8P &outImage, TFont::Impl *pimpl, wchar_t charcode) {
|
|
|
|
OSStatus status;
|
|
|
|
UniChar subString[2];
|
|
|
|
subString[0] = charcode;
|
|
|
|
subString[1] = 0;
|
|
|
|
UniCharCount length = sizeof(subString) / sizeof(UniChar);
|
|
|
|
|
|
|
|
status = ATSUCreateTextLayoutWithTextPtr(
|
|
|
|
subString, kATSUFromTextBeginning, kATSUToTextEnd, length, 1, &length,
|
|
|
|
&(pimpl->m_style), &(pimpl->m_layout));
|
|
|
|
assert(status == noErr);
|
|
|
|
|
|
|
|
ATSTrapezoid glyphBounds;
|
|
|
|
status = ATSUGetGlyphBounds(pimpl->m_layout, 0, 0, kATSUFromTextBeginning,
|
|
|
|
kATSUToTextEnd, kATSUseFractionalOrigins, 1,
|
|
|
|
&glyphBounds, NULL);
|
|
|
|
|
|
|
|
int height =
|
|
|
|
FixedToInt(glyphBounds.lowerLeft.y) - FixedToInt(glyphBounds.upperLeft.y);
|
|
|
|
int width = tmax(FixedToInt(glyphBounds.lowerRight.x),
|
|
|
|
FixedToInt(glyphBounds.upperRight.x)) -
|
|
|
|
tmin(FixedToInt(glyphBounds.lowerLeft.x),
|
|
|
|
FixedToInt(glyphBounds.upperLeft.x));
|
|
|
|
|
|
|
|
outImage = TRasterGR8P(width, height);
|
|
|
|
TPixelGR8 bgp;
|
|
|
|
bgp.value = 255;
|
|
|
|
outImage->fill(bgp);
|
|
|
|
void *data = outImage->getRawData();
|
|
|
|
|
|
|
|
CGColorSpaceRef grayColorSpace =
|
|
|
|
CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);
|
|
|
|
CGContextRef gContext = CGBitmapContextCreate(
|
|
|
|
data, width, height, 8, width, grayColorSpace, kCGImageAlphaNone);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
#if defined(DEBUG) || defined(_DEBUG)
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
int bpc = CGBitmapContextGetBitsPerComponent(gContext);
|
|
|
|
if (bpc != 8) std::cout << "BitsPerComponent: " << bpc << std::endl;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
int bpp = CGBitmapContextGetBitsPerPixel(gContext);
|
|
|
|
if (bpp != 8) std::cout << "BitsPerPixel: " << bpp << std::endl;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
int bytesPerRow = CGBitmapContextGetBytesPerRow(gContext);
|
|
|
|
int newWidth = CGBitmapContextGetWidth(gContext);
|
|
|
|
if (bytesPerRow != width || newWidth != width)
|
|
|
|
std::cout << "BytesPerRow: " << bytesPerRow << " Old width= " << width
|
|
|
|
<< " New width= " << newWidth << std::endl;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
int newHeight = CGBitmapContextGetHeight(gContext);
|
|
|
|
if (newHeight != height)
|
|
|
|
std::cout << " Old height= " << height << " New height= " << newHeight
|
|
|
|
<< std::endl;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
assert(CGBitmapContextGetColorSpace(gContext) == grayColorSpace);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
ATSUAttributeTag tags[1];
|
|
|
|
ByteCount sizes[1];
|
|
|
|
ATSUAttributeValuePtr values[1];
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
tags[0] = kATSUCGContextTag;
|
|
|
|
sizes[0] = sizeof(CGContextRef);
|
|
|
|
values[0] = &gContext;
|
|
|
|
status = ATSUSetLayoutControls(pimpl->m_layout, 1, tags, sizes, values);
|
|
|
|
assert(status == noErr);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
ATSUDrawText(pimpl->m_layout, kATSUFromTextBeginning, kATSUToTextEnd, 0,
|
|
|
|
glyphBounds.lowerLeft.y);
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
TPoint TFont::drawChar(TRasterGR8P &outImage, TPoint &unused, wchar_t charcode,
|
|
|
|
wchar_t nextCharCode) const {
|
|
|
|
appDrawChar(outImage, m_pimpl, charcode);
|
|
|
|
outImage->yMirror();
|
|
|
|
return getDistance(charcode, nextCharCode);
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
TPoint TFont::drawChar(TRasterCM32P &outImage, TPoint &unused, int inkId,
|
|
|
|
wchar_t charcode, wchar_t nextCharCode) const {
|
|
|
|
TRasterGR8P grayAppImage;
|
|
|
|
appDrawChar(grayAppImage, m_pimpl, charcode);
|
|
|
|
|
|
|
|
int lx = grayAppImage->getLx();
|
|
|
|
int ly = grayAppImage->getLy();
|
|
|
|
|
|
|
|
outImage = TRasterCM32P(lx, ly);
|
|
|
|
|
|
|
|
assert(TPixelCM32::getMaxTone() == 255);
|
|
|
|
TPixelCM32 bgColor(0, 0, TPixelCM32::getMaxTone());
|
|
|
|
grayAppImage->lock();
|
|
|
|
outImage->lock();
|
|
|
|
int ty = 0;
|
|
|
|
for (int gy = ly - 1; gy >= 0; --gy, ++ty) {
|
|
|
|
TPixelGR8 *srcPix = grayAppImage->pixels(gy);
|
|
|
|
TPixelCM32 *tarPix = outImage->pixels(ty);
|
|
|
|
for (int x = 0; x < lx; ++x) {
|
|
|
|
int tone = srcPix->value;
|
|
|
|
|
|
|
|
if (tone == 255)
|
|
|
|
*tarPix = bgColor;
|
|
|
|
else
|
|
|
|
*tarPix = TPixelCM32(inkId, 0, tone);
|
|
|
|
|
|
|
|
++srcPix;
|
|
|
|
++tarPix;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
grayAppImage->unlock();
|
|
|
|
outImage->unlock();
|
|
|
|
|
|
|
|
return getDistance(charcode, nextCharCode);
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
TPoint TFont::getDistance(wchar_t firstChar, wchar_t secondChar) const {
|
|
|
|
OSStatus status;
|
|
|
|
UniChar subString[2];
|
|
|
|
subString[0] = firstChar;
|
|
|
|
subString[1] = secondChar;
|
|
|
|
UniCharCount length = sizeof(subString) / sizeof(UniChar);
|
|
|
|
|
|
|
|
status = ATSUCreateTextLayoutWithTextPtr(
|
|
|
|
subString, kATSUFromTextBeginning, kATSUToTextEnd, length, 1, &length,
|
|
|
|
&(m_pimpl->m_style), &(m_pimpl->m_layout));
|
|
|
|
assert(status == noErr);
|
|
|
|
|
|
|
|
MyGlyphRecord *glyphRecordArray;
|
|
|
|
ItemCount numGlyphs;
|
|
|
|
|
|
|
|
// Get the array of glyph information
|
|
|
|
GetGlyphIDsAndPositions(m_pimpl->m_layout, kATSUFromTextBeginning,
|
|
|
|
kATSUToTextEnd, &glyphRecordArray, &numGlyphs);
|
|
|
|
|
|
|
|
assert(numGlyphs >= 2);
|
|
|
|
|
|
|
|
assert(glyphRecordArray[0].relativeOrigin.x == 0);
|
|
|
|
int advance = (int)(glyphRecordArray[1].relativeOrigin.x -
|
|
|
|
glyphRecordArray[0].relativeOrigin.x);
|
|
|
|
if (advance == 0) {
|
|
|
|
subString[1] = 0;
|
|
|
|
status = ATSUCreateTextLayoutWithTextPtr(
|
|
|
|
subString, kATSUFromTextBeginning, kATSUToTextEnd, length, 1, &length,
|
|
|
|
&(m_pimpl->m_style), &(m_pimpl->m_layout));
|
|
|
|
|
|
|
|
GetGlyphIDsAndPositions(m_pimpl->m_layout, kATSUFromTextBeginning,
|
|
|
|
kATSUToTextEnd, &glyphRecordArray, &numGlyphs);
|
|
|
|
advance = (int)(glyphRecordArray[1].relativeOrigin.x -
|
|
|
|
glyphRecordArray[0].relativeOrigin.x);
|
|
|
|
}
|
|
|
|
return TPoint(advance, 0);
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
int TFont::getMaxHeight() const {
|
|
|
|
return m_pimpl->m_ascender - m_pimpl->m_descender;
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
int TFont::getMaxWidth() const {
|
|
|
|
assert(!"not implemented yet");
|
|
|
|
return 100;
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
int TFont::getLineAscender() const { return m_pimpl->m_ascender; }
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
int TFont::getLineDescender() const { return m_pimpl->m_descender; }
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
bool TFont::hasKerning() const { return true; }
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
bool TFont::hasVertical() const { return false; }
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
#include <map>
|
|
|
|
|
|
|
|
typedef std::map<std::string, ATSUFontID> FontFamily;
|
|
|
|
|
|
|
|
typedef std::map<std::string, FontFamily> FamilyMap;
|
|
|
|
|
|
|
|
struct TFontManager::Impl {
|
2016-06-15 18:43:10 +12:00
|
|
|
FamilyMap m_families;
|
|
|
|
bool m_loaded;
|
|
|
|
ATSUFontID m_currentAtsuFontId;
|
|
|
|
TFont *m_currentFont;
|
|
|
|
wstring m_currentFamily;
|
|
|
|
wstring m_currentTypeface;
|
|
|
|
int m_size;
|
|
|
|
|
|
|
|
Impl()
|
|
|
|
: m_currentAtsuFontId(0), m_currentFont(0), m_loaded(false), m_size(70) {}
|
|
|
|
|
|
|
|
bool setFontName(ATSUFontID fontId, int platform, int script, int lang);
|
|
|
|
bool addFont(ATSUFontID);
|
|
|
|
void loadFontNames();
|
|
|
|
bool setFont(std::wstring family, std::wstring style);
|
2016-03-19 06:57:51 +13:00
|
|
|
};
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
bool TFontManager::Impl::setFontName(ATSUFontID fontId, int platform,
|
|
|
|
int script, int lang) {
|
|
|
|
ByteCount oActualNameLength;
|
|
|
|
ItemCount oFontCount;
|
|
|
|
OSStatus status;
|
|
|
|
|
|
|
|
char *buffer = 0;
|
|
|
|
char *buffer2 = 0;
|
|
|
|
|
|
|
|
// chiedo la lunhezza del Full Family Name per allocare il buffer
|
|
|
|
status = ATSUFindFontName(fontId, kFontFullName, platform, script, lang, 0, 0,
|
|
|
|
&oActualNameLength, 0);
|
|
|
|
|
|
|
|
if (status != noErr || oActualNameLength <= 1) return false;
|
|
|
|
|
|
|
|
buffer = new char[oActualNameLength + 1];
|
|
|
|
// chiedo il Full Family Name
|
|
|
|
status = ATSUFindFontName(fontId, kFontFullName, platform, script, lang,
|
|
|
|
oActualNameLength, buffer, &oActualNameLength,
|
|
|
|
&oFontCount);
|
|
|
|
|
|
|
|
if (status != noErr || oActualNameLength <= 1 || buffer[0] == '\0') {
|
|
|
|
delete[] buffer;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
buffer[oActualNameLength] = '\0';
|
|
|
|
|
|
|
|
//-------------------
|
|
|
|
|
|
|
|
// chiedo la lunhezza del Typeface Name per allocare il buffer
|
|
|
|
status = ATSUFindFontName(fontId, kFontStyleName, platform, script, lang, 0,
|
|
|
|
0, &oActualNameLength, 0);
|
|
|
|
|
|
|
|
if (status != noErr || oActualNameLength <= 1) {
|
|
|
|
delete[] buffer;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
buffer2 = new char[oActualNameLength + 1];
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
// chiedo il Typeface Name
|
|
|
|
status = ATSUFindFontName(fontId, kFontStyleName, platform, script, lang,
|
|
|
|
oActualNameLength, buffer2, &oActualNameLength,
|
|
|
|
&oFontCount);
|
|
|
|
|
|
|
|
if (status != noErr || oActualNameLength <= 1 || buffer2[0] == '\0') {
|
|
|
|
delete[] buffer;
|
|
|
|
delete[] buffer2;
|
|
|
|
return false;
|
|
|
|
} else
|
|
|
|
buffer2[oActualNameLength] = '\0';
|
|
|
|
|
|
|
|
string s_family(buffer);
|
|
|
|
FontFamily &family = m_families[s_family];
|
|
|
|
family[string(buffer2)] = fontId;
|
|
|
|
delete[] buffer;
|
|
|
|
delete[] buffer2;
|
|
|
|
return true;
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
bool TFontManager::Impl::addFont(ATSUFontID fontId) {
|
|
|
|
int platform, script, lang;
|
|
|
|
|
|
|
|
// per ottimizzare, ciclo solo sui valori
|
|
|
|
// piu' comuni
|
|
|
|
for (lang = -1; lang <= 0; lang++)
|
|
|
|
for (platform = -1; platform <= 1; platform++)
|
|
|
|
for (script = -1; script <= 0; script++)
|
|
|
|
if (setFontName(fontId, platform, script, lang)) return true;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
// poi li provo tutti
|
|
|
|
for (lang = -1; lang <= 139; lang++)
|
|
|
|
for (script = -1; script <= 32; script++)
|
|
|
|
for (platform = -1; platform <= 4; platform++) {
|
|
|
|
// escludo quelli nel tri-ciclo for precedente.
|
|
|
|
// Purtoppo si deve fare cosi:
|
|
|
|
// non si puo' fare partendo con indici piu' alti nei cicli for!
|
|
|
|
if (-1 <= lang && lang <= 0 && -1 <= script && script <= 0 &&
|
|
|
|
-1 <= platform && platform <= 1)
|
|
|
|
continue;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
if (setFontName(fontId, platform, script, lang)) return true;
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
return false;
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
void TFontManager::Impl::loadFontNames() {
|
|
|
|
if (m_loaded) return;
|
|
|
|
|
|
|
|
ItemCount oFontCount, fontCount;
|
|
|
|
ATSUFontCount(&oFontCount);
|
|
|
|
fontCount = oFontCount;
|
|
|
|
ATSUFontID *oFontIDs = new ATSUFontID[fontCount];
|
|
|
|
ATSUGetFontIDs(oFontIDs, fontCount, &oFontCount);
|
|
|
|
assert(fontCount == oFontCount);
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < fontCount; i++) addFont(oFontIDs[i]);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
delete[] oFontIDs;
|
|
|
|
m_loaded = true;
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
bool TFontManager::Impl::setFont(std::wstring family, std::wstring typeface) {
|
|
|
|
if (family == m_currentFamily &&
|
|
|
|
(typeface == m_currentTypeface || typeface == L""))
|
|
|
|
return false;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
FamilyMap::iterator family_it = m_families.find(toString(family));
|
|
|
|
if (family_it == m_families.end()) throw TFontCreationError();
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
m_currentFamily = family;
|
|
|
|
FontFamily::iterator style_it;
|
|
|
|
if (typeface == L"") {
|
|
|
|
style_it = ((*family_it).second).find(toString(m_currentTypeface));
|
|
|
|
if (style_it == (*family_it).second.end())
|
|
|
|
style_it = ((*family_it).second).begin();
|
|
|
|
|
|
|
|
typeface = toWideString(style_it->first);
|
|
|
|
} else
|
|
|
|
style_it = ((*family_it).second).find(toString(typeface));
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
if (style_it == (*family_it).second.end()) throw TFontCreationError();
|
|
|
|
|
|
|
|
m_currentTypeface = typeface;
|
|
|
|
m_currentAtsuFontId = (*style_it).second;
|
|
|
|
return true;
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
TFontManager::TFontManager() { m_pimpl = new TFontManager::Impl(); }
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
TFontManager::~TFontManager() { delete m_pimpl; }
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
TFontManager *TFontManager::instance() {
|
|
|
|
static TFontManager theManager;
|
|
|
|
return &theManager;
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
void TFontManager::loadFontNames() { m_pimpl->loadFontNames(); }
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
void TFontManager::setFamily(const wstring family) {
|
|
|
|
bool changed = m_pimpl->setFont(family, L"");
|
|
|
|
if (changed) {
|
|
|
|
delete m_pimpl->m_currentFont;
|
|
|
|
m_pimpl->m_currentFont =
|
|
|
|
new TFont(m_pimpl->m_currentAtsuFontId, m_pimpl->m_size);
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
void TFontManager::setTypeface(const wstring typeface) {
|
|
|
|
bool changed = m_pimpl->setFont(m_pimpl->m_currentFamily, typeface);
|
|
|
|
if (changed) {
|
|
|
|
delete m_pimpl->m_currentFont;
|
|
|
|
m_pimpl->m_currentFont =
|
|
|
|
new TFont(m_pimpl->m_currentAtsuFontId, m_pimpl->m_size);
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
void TFontManager::setSize(int size) {
|
|
|
|
if (m_pimpl->m_size != size) {
|
|
|
|
m_pimpl->m_size = size;
|
|
|
|
delete m_pimpl->m_currentFont;
|
|
|
|
m_pimpl->m_currentFont =
|
|
|
|
new TFont(m_pimpl->m_currentAtsuFontId, m_pimpl->m_size);
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
wstring TFontManager::getCurrentFamily() const {
|
|
|
|
return m_pimpl->m_currentFamily;
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
wstring TFontManager::getCurrentTypeface() const {
|
|
|
|
return m_pimpl->m_currentTypeface;
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
TFont *TFontManager::getCurrentFont() {
|
|
|
|
if (m_pimpl->m_currentFont) return m_pimpl->m_currentFont;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
if (!m_pimpl->m_currentFont) loadFontNames();
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
assert(!m_pimpl->m_families.empty());
|
|
|
|
setFamily(toWideString(m_pimpl->m_families.begin()->first));
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
return m_pimpl->m_currentFont;
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
void TFontManager::getAllFamilies(vector<wstring> &families) const {
|
|
|
|
families.clear();
|
|
|
|
families.reserve(m_pimpl->m_families.size());
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
FamilyMap::iterator it = m_pimpl->m_families.begin();
|
|
|
|
for (; it != m_pimpl->m_families.end(); ++it) {
|
|
|
|
families.push_back(toWideString(it->first));
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
void TFontManager::getAllTypefaces(vector<wstring> &typefaces) const {
|
|
|
|
typefaces.clear();
|
|
|
|
FamilyMap::iterator it_family =
|
|
|
|
m_pimpl->m_families.find(toString(m_pimpl->m_currentFamily));
|
|
|
|
if (it_family == m_pimpl->m_families.end()) return;
|
|
|
|
FontFamily &typefaceSet = it_family->second;
|
|
|
|
|
|
|
|
typefaces.reserve(typefaceSet.size());
|
|
|
|
FontFamily::iterator it_typeface = typefaceSet.begin();
|
|
|
|
for (; it_typeface != typefaceSet.end(); ++it_typeface) {
|
|
|
|
typefaces.push_back(toWideString(it_typeface->first));
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void TFontManager::setVertical(bool vertical) {}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
#endif
|