summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/xetexdir/XeTeXLayoutInterface.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/web2c/xetexdir/XeTeXLayoutInterface.cpp')
-rw-r--r--Build/source/texk/web2c/xetexdir/XeTeXLayoutInterface.cpp981
1 files changed, 404 insertions, 577 deletions
diff --git a/Build/source/texk/web2c/xetexdir/XeTeXLayoutInterface.cpp b/Build/source/texk/web2c/xetexdir/XeTeXLayoutInterface.cpp
index eb566b173e4..f01b5b1699e 100644
--- a/Build/source/texk/web2c/xetexdir/XeTeXLayoutInterface.cpp
+++ b/Build/source/texk/web2c/xetexdir/XeTeXLayoutInterface.cpp
@@ -1,9 +1,10 @@
/****************************************************************************\
Part of the XeTeX typesetting system
- copyright (c) 1994-2008 by SIL International
- copyright (c) 2009-2012 by Jonathan Kew
+ Copyright (c) 1994-2008 by SIL International
+ Copyright (c) 2009-2012 by Jonathan Kew
+ Copyright (c) 2012 by Khaled Hosny
- Written by Jonathan Kew
+ SIL Author(s): Jonathan Kew
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -30,58 +31,33 @@ use or other dealings in this Software without prior written
authorization from the copyright holders.
\****************************************************************************/
-#include "unicode/platform.h" // We need this first
+#include <unicode/platform.h> // We need this first
+#include <unicode/ubidi.h>
+#include <unicode/utext.h>
#include "XeTeXLayoutInterface.h"
-
-#include "XeTeXOTLayoutEngine.h"
#include "XeTeXFontInst.h"
#ifdef XETEX_MAC
#include "XeTeXFontInst_Mac.h"
#endif
#include "XeTeXFontInst_FT2.h"
-
#include "XeTeXFontMgr.h"
-
#include "XeTeXswap.h"
-#ifdef XETEX_GRAPHITE
-#include "XeTeXGrLayout.h"
-#endif
-
-#include "layout/ICUFeatures.h"
-#include "layout/ScriptAndLanguage.h"
-
-#include "unicode/ubidi.h"
-#include "unicode/utext.h"
-
-#include <math.h>
-/* apparently M_PI isn't defined by <math.h> under VC++ */
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
struct XeTeXLayoutEngine_rec
- /* this is used for both ICU and Graphite, because so much of the font stuff is common;
- however, it is not possible to call ICU-specific things like layoutChars for a
- Graphite-based engine, or Graphite functions for an ICU one! */
{
- LayoutEngine* layoutEngine;
XeTeXFontInst* font;
PlatformFontRef fontRef;
- UInt32 scriptTag;
- UInt32 languageTag;
- UInt32* addedFeatures;
- UInt32* removedFeatures;
+ char* script;
+ char* language;
+ hb_feature_t* features;
+ char** shapers;
+ int nFeatures;
UInt32 rgbValue;
float extend;
float slant;
float embolden;
-#ifdef XETEX_GRAPHITE
- gr::Segment* grSegment;
- XeTeXGrFont* grFont;
- XeTeXGrTextSource* grSource;
-#endif
+ hb_buffer_t* hbBuffer;
};
/*******************************************************************/
@@ -120,17 +96,17 @@ void terminatefontmanager()
XeTeXFont createFont(PlatformFontRef fontRef, Fixed pointSize)
{
- LEErrorCode status = LE_NO_ERROR;
+ int status = 0;
#ifdef XETEX_MAC
- XeTeXFontInst* font = new XeTeXFontInst_Mac((ATSFontRef)fontRef, Fix2X(pointSize), status);
+ XeTeXFontInst* font = new XeTeXFontInst_Mac((ATSFontRef)fontRef, Fix2D(pointSize), status);
#else
FcChar8* pathname = 0;
FcPatternGetString(fontRef, FC_FILE, 0, &pathname);
int index;
FcPatternGetInteger(fontRef, FC_INDEX, 0, &index);
- XeTeXFontInst* font = new XeTeXFontInst_FT2((const char*)pathname, index, Fix2X(pointSize), status);
+ XeTeXFontInst* font = new XeTeXFontInst_FT2((const char*)pathname, index, Fix2D(pointSize), status);
#endif
- if (LE_FAILURE(status)) {
+ if (status != 0) {
delete font;
return NULL;
}
@@ -139,9 +115,9 @@ XeTeXFont createFont(PlatformFontRef fontRef, Fixed pointSize)
XeTeXFont createFontFromFile(const char* filename, int index, Fixed pointSize)
{
- LEErrorCode status = LE_NO_ERROR;
- XeTeXFontInst* font = new XeTeXFontInst_FT2(filename, index, Fix2X(pointSize), status);
- if (LE_FAILURE(status)) {
+ int status = 0;
+ XeTeXFontInst* font = new XeTeXFontInst_FT2(filename, index, Fix2D(pointSize), status);
+ if (status != 0) {
delete font;
return NULL;
}
@@ -163,6 +139,11 @@ char getReqEngine()
return XeTeXFontMgr::GetFontManager()->getReqEngine();
}
+void setReqEngine(char reqEngine)
+{
+ XeTeXFontMgr::GetFontManager()->setReqEngine(reqEngine);
+}
+
const char* getFullName(PlatformFontRef fontRef)
{
return XeTeXFontMgr::GetFontManager()->getFullName(fontRef);
@@ -201,323 +182,347 @@ void* getFontTablePtr(XeTeXFont font, UInt32 tableTag)
Fixed getSlant(XeTeXFont font)
{
float italAngle = ((XeTeXFontInst*)font)->getItalicAngle();
- return X2Fix(tan(-italAngle * M_PI / 180.0));
+ return D2Fix(tan(-italAngle * M_PI / 180.0));
}
-static const ScriptListTable*
-getLargerScriptListTable(XeTeXFont font)
+static UInt32
+getLargerScriptListTable(XeTeXFont font, hb_tag_t** scriptList, hb_tag_t* tableTag)
{
- const ScriptListTable* scriptListSub = NULL;
- const ScriptListTable* scriptListPos = NULL;
-
- const GlyphSubstitutionTableHeader* gsubTable = (const GlyphSubstitutionTableHeader*)((XeTeXFontInst*)font)->getFontTable(kGSUB);
- UInt32 scriptCountSub = 0;
- if (gsubTable != NULL) {
- scriptListSub = (const ScriptListTable*)((const char*)gsubTable + SWAP(gsubTable->scriptListOffset));
- scriptCountSub = SWAP(scriptListSub->scriptCount);
- }
+ hb_face_t* face = hb_font_get_face(((XeTeXFontInst*)font)->hbFont);
- const GlyphPositioningTableHeader* gposTable = (const GlyphPositioningTableHeader*)((XeTeXFontInst*)font)->getFontTable(kGPOS);
- UInt32 scriptCountPos = 0;
- if (gposTable != NULL) {
- scriptListPos = (const ScriptListTable*)((const char*)gposTable + SWAP(gposTable->scriptListOffset));
- scriptCountPos = SWAP(scriptListPos->scriptCount);
- }
+ hb_tag_t* scriptListSub = NULL;
+ hb_tag_t* scriptListPos = NULL;
+
+ uint32_t scriptCountSub = hb_ot_layout_table_get_script_tags(face, HB_OT_TAG_GSUB, 0, NULL, NULL);
+ scriptListSub = (hb_tag_t*) xmalloc(scriptCountSub * sizeof(hb_tag_t*));
+ hb_ot_layout_table_get_script_tags(face, HB_OT_TAG_GSUB, 0, &scriptCountSub, scriptListSub);
- return scriptCountPos > scriptCountSub ? scriptListPos : scriptListSub;
+ uint32_t scriptCountPos = hb_ot_layout_table_get_script_tags(face, HB_OT_TAG_GPOS, 0, NULL, NULL);
+ scriptListPos = (hb_tag_t*) xmalloc(scriptCountPos * sizeof(hb_tag_t*));
+ hb_ot_layout_table_get_script_tags(face, HB_OT_TAG_GSUB, 0, &scriptCountPos, scriptListPos);
+
+ if (scriptCountSub > scriptCountPos) {
+ if (scriptList != NULL)
+ *scriptList = scriptListSub;
+ if (tableTag != NULL)
+ *tableTag = HB_OT_TAG_GSUB;
+ return scriptCountSub;
+ } else {
+ if (scriptList != NULL)
+ *scriptList = scriptListPos;
+ if (tableTag != NULL)
+ *tableTag = HB_OT_TAG_GPOS;
+ return scriptCountPos;
+ }
}
UInt32 countScripts(XeTeXFont font)
{
- const ScriptListTable* scriptList = getLargerScriptListTable(font);
- if (scriptList == NULL)
- return 0;
-
- return SWAP(scriptList->scriptCount);
+ return getLargerScriptListTable(font, NULL, NULL);
}
UInt32 getIndScript(XeTeXFont font, UInt32 index)
{
- const ScriptListTable* scriptList = getLargerScriptListTable(font);
+ hb_tag_t* scriptList;
+
+ UInt32 scriptCount = getLargerScriptListTable(font, &scriptList, NULL);
if (scriptList == NULL)
return 0;
- if (index < SWAP(scriptList->scriptCount))
- return SWAPT(scriptList->scriptRecordArray[index].tag);
+ if (index < scriptCount)
+ return scriptList[index];
return 0;
}
UInt32 countScriptLanguages(XeTeXFont font, UInt32 script)
{
- const ScriptListTable* scriptList = getLargerScriptListTable(font);
+ hb_face_t* face = hb_font_get_face(((XeTeXFontInst*)font)->hbFont);
+ hb_tag_t* scriptList;
+ hb_tag_t tableTag;
+
+ UInt32 scriptCount = getLargerScriptListTable(font, &scriptList, &tableTag);
if (scriptList == NULL)
return 0;
- const ScriptTable* scriptTable = scriptList->findScript(script);
- if (scriptTable == NULL)
- return 0;
-
- UInt32 langCount = SWAP(scriptTable->langSysCount);
-
- return langCount;
+ for (int i = 0; i < scriptCount; i++) {
+ if (scriptList[i] == script) {
+ return hb_ot_layout_script_get_language_tags (face, tableTag, i, 0, NULL, NULL);
+ }
+ }
}
UInt32 getIndScriptLanguage(XeTeXFont font, UInt32 script, UInt32 index)
{
- const ScriptListTable* scriptList = getLargerScriptListTable(font);
+ hb_face_t* face = hb_font_get_face(((XeTeXFontInst*)font)->hbFont);
+ hb_tag_t* scriptList;
+ hb_tag_t tableTag;
+
+ UInt32 scriptCount = getLargerScriptListTable(font, &scriptList, &tableTag);
if (scriptList == NULL)
return 0;
- const ScriptTable* scriptTable = scriptList->findScript(script);
- if (scriptTable == NULL)
- return 0;
+ for (int i = 0; i < scriptCount; i++) {
+ if (scriptList[i] == script) {
+ uint32_t langCount = hb_ot_layout_script_get_language_tags(face, tableTag, i, 0, NULL, NULL);
+ hb_tag_t* langList = (hb_tag_t*) xmalloc(langCount * sizeof(hb_tag_t*));
+ hb_ot_layout_script_get_language_tags(face, tableTag, i, 0, &langCount, langList);
- if (index < SWAP(scriptTable->langSysCount))
- return SWAPT(scriptTable->langSysRecordArray[index].tag);
+ if (index < langCount)
+ return langList[index];
- return 0;
+ return 0;
+ }
+ }
}
UInt32 countFeatures(XeTeXFont font, UInt32 script, UInt32 language)
{
- UInt32 total = 0;
- const GlyphLookupTableHeader* table;
+ hb_face_t* face = hb_font_get_face(((XeTeXFontInst*)font)->hbFont);
+ UInt32 total = 0;
+
for (int i = 0; i < 2; ++i) {
- table = (const GlyphLookupTableHeader*)((XeTeXFontInst*)font)->getFontTable(i == 0 ? kGSUB : kGPOS);
- if (table != NULL) {
- const ScriptListTable* scriptList = (const ScriptListTable*)((const char*)table + SWAP(table->scriptListOffset));
- const ScriptTable* scriptTable = scriptList->findScript(script);
- if (scriptTable != NULL) {
- const LangSysTable* langTable = scriptTable->findLanguage(language, (language != 0));
- if (langTable != NULL) {
- total += SWAP(langTable->featureCount);
- if (langTable->reqFeatureIndex != 0xffff)
- total += 1;
- }
+ uint32_t scriptIndex, langIndex = 0;
+ hb_tag_t tableTag = i == 0 ? HB_OT_TAG_GSUB : HB_OT_TAG_GPOS;
+ if (hb_ot_layout_table_find_script(face, tableTag, script, &scriptIndex)) {
+ if (hb_ot_layout_script_find_language(face, tableTag, scriptIndex, language, &langIndex) || language == 0) {
+ total += hb_ot_layout_language_get_feature_tags(face, tableTag, scriptIndex, langIndex, 0, NULL, NULL);
}
}
}
-
+
return total;
}
UInt32 getIndFeature(XeTeXFont font, UInt32 script, UInt32 language, UInt32 index)
{
- const GlyphLookupTableHeader* table;
- UInt16 featureIndex = 0xffff;
+ hb_face_t* face = hb_font_get_face(((XeTeXFontInst*)font)->hbFont);
+
for (int i = 0; i < 2; ++i) {
- table = (const GlyphLookupTableHeader*)((XeTeXFontInst*)font)->getFontTable(i == 0 ? kGSUB : kGPOS);
- if (table != NULL) {
- const ScriptListTable* scriptList = (const ScriptListTable*)((const char*)table + SWAP(table->scriptListOffset));
- const ScriptTable* scriptTable = scriptList->findScript(script);
- if (scriptTable != NULL) {
- const LangSysTable* langTable = scriptTable->findLanguage(language, (language != 0));
- if (langTable != NULL) {
- if (SWAP(langTable->reqFeatureIndex) != 0xffff)
- if (index == 0)
- featureIndex = SWAP(langTable->reqFeatureIndex);
- else
- index -= 1;
- if (index < SWAP(langTable->featureCount))
- featureIndex = SWAP(langTable->featureIndexArray[index]);
- index -= SWAP(langTable->featureCount);
- }
- }
- if (featureIndex != 0xffff) {
- LETag featureTag;
- const FeatureListTable* featureListTable = (const FeatureListTable*)((const char*)table + SWAP(table->featureListOffset));
- (void)featureListTable->getFeatureTable(featureIndex, &featureTag);
- return featureTag;
+ uint32_t scriptIndex, langIndex = 0;
+ hb_tag_t tableTag = i == 0 ? HB_OT_TAG_GSUB : HB_OT_TAG_GPOS;
+ if (hb_ot_layout_table_find_script(face, tableTag, script, &scriptIndex)) {
+ if (hb_ot_layout_script_find_language(face, tableTag, scriptIndex, language, &langIndex) || language == 0) {
+ uint32_t featCount = hb_ot_layout_language_get_feature_tags(face, tableTag, scriptIndex, langIndex, 0, NULL, NULL);
+ hb_tag_t* featList = (hb_tag_t*) xmalloc(featCount * sizeof(hb_tag_t*));
+ hb_ot_layout_language_get_feature_tags(face, tableTag, scriptIndex, langIndex, 0, &featCount, featList);
+
+ if (index < featCount)
+ return featList[index];
+
+ index -= featCount;
}
}
}
-
+
return 0;
}
-#ifdef XETEX_GRAPHITE
UInt32 countGraphiteFeatures(XeTeXLayoutEngine engine)
{
- std::pair<gr::FeatureIterator, gr::FeatureIterator> fi = engine->grFont->getFeatures();
- UInt32 rval = 0;
- while (fi.first != fi.second) {
- ++rval;
- ++fi.first;
- }
+ uint32_t rval = 0;
+
+ hb_face_t* hbFace = hb_font_get_face(engine->font->hbFont);
+ gr_face* grFace = hb_graphite2_face_get_gr_face(hbFace);
+
+ if (grFace != NULL)
+ rval = gr_face_n_fref(grFace);
+
return rval;
}
UInt32 getGraphiteFeatureCode(XeTeXLayoutEngine engine, UInt32 index)
{
- std::pair<gr::FeatureIterator, gr::FeatureIterator> fi = engine->grFont->getFeatures();
- while (index > 0 && fi.first != fi.second) {
- --index;
- ++fi.first;
+ uint32_t rval = 0;
+
+ hb_face_t* hbFace = hb_font_get_face(engine->font->hbFont);
+ gr_face* grFace = hb_graphite2_face_get_gr_face(hbFace);
+
+ if (grFace != NULL) {
+ const gr_feature_ref* feature = gr_face_fref(grFace, index);
+ rval = gr_fref_id(feature);
}
- if (fi.first != fi.second)
- return *fi.first;
- return 0;
+
+ return rval;
}
-UInt32 countGraphiteFeatureSettings(XeTeXLayoutEngine engine, UInt32 feature)
+UInt32 countGraphiteFeatureSettings(XeTeXLayoutEngine engine, UInt32 featureID)
{
- std::pair<gr::FeatureIterator, gr::FeatureIterator> fi = engine->grFont->getFeatures();
- while (fi.first != fi.second && *fi.first != feature)
- ++fi.first;
- if (fi.first != fi.second) {
- std::pair<gr::FeatureSettingIterator, gr::FeatureSettingIterator>
- si = engine->grFont->getFeatureSettings(fi.first);
- UInt32 rval = 0;
- while (si.first != si.second) {
- ++rval;
- ++si.first;
- }
- return rval;
+ uint32_t rval = 0;
+
+ hb_face_t* hbFace = hb_font_get_face(engine->font->hbFont);
+ gr_face* grFace = hb_graphite2_face_get_gr_face(hbFace);
+
+ if (grFace != NULL) {
+ const gr_feature_ref* feature = gr_face_find_fref(grFace, featureID);
+ rval = gr_fref_n_values(feature);
}
- return 0;
+
+ return rval;
}
-UInt32 getGraphiteFeatureSettingCode(XeTeXLayoutEngine engine, UInt32 feature, UInt32 index)
+UInt32 getGraphiteFeatureSettingCode(XeTeXLayoutEngine engine, UInt32 featureID, UInt32 index)
{
- std::pair<gr::FeatureIterator, gr::FeatureIterator> fi = engine->grFont->getFeatures();
- while (fi.first != fi.second && *fi.first != feature)
- ++fi.first;
- if (fi.first != fi.second) {
- std::pair<gr::FeatureSettingIterator, gr::FeatureSettingIterator>
- si = engine->grFont->getFeatureSettings(fi.first);
- while (index > 0 && si.first != si.second) {
- --index;
- ++si.first;
- }
- if (si.first != si.second)
- return *si.first;
+ uint32_t rval = 0;
+
+ hb_face_t* hbFace = hb_font_get_face(engine->font->hbFont);
+ gr_face* grFace = hb_graphite2_face_get_gr_face(hbFace);
+
+ if (grFace != NULL) {
+ const gr_feature_ref* feature = gr_face_find_fref(grFace, featureID);
+ rval = gr_fref_value(feature, index);
}
- return 0;
+
+ return rval;
}
-UInt32 getGraphiteFeatureDefaultSetting(XeTeXLayoutEngine engine, UInt32 feature)
+void getGraphiteFeatureLabel(XeTeXLayoutEngine engine, UInt32 featureID, char* buf)
{
- std::pair<gr::FeatureIterator, gr::FeatureIterator> fi = engine->grFont->getFeatures();
- while (fi.first != fi.second && *fi.first != feature)
- ++fi.first;
- if (fi.first != fi.second) {
- gr::FeatureSettingIterator si = engine->grFont->getDefaultFeatureValue(fi.first);
- return *si;
+ buf[0] = '\0';
+
+ hb_face_t* hbFace = hb_font_get_face(engine->font->hbFont);
+ gr_face* grFace = hb_graphite2_face_get_gr_face(hbFace);
+
+ if (grFace != NULL) {
+ const gr_feature_ref* feature = gr_face_find_fref(grFace, featureID);
+ uint32_t len = 0;
+ uint16_t langID = 0x409;
+
+ buf = (char*) gr_fref_label(feature, &langID, gr_utf8, &len);
+
+ if (len > 128 + 1) { // 128 is set in XeTeX_ext.c
+ buf = (char*) realloc(buf, len + 1);
+ buf = (char*) gr_fref_label(feature, &langID, gr_utf8, &len);
+ }
+
+ buf[len + 1] = '\0';
}
- return 0;
}
-void getGraphiteFeatureLabel(XeTeXLayoutEngine engine, UInt32 feature, unsigned short* buf)
+void getGraphiteFeatureSettingLabel(XeTeXLayoutEngine engine, UInt32 featureID, UInt32 settingID, char* buf)
{
- buf[0] = 0;
- std::pair<gr::FeatureIterator, gr::FeatureIterator> fi = engine->grFont->getFeatures();
- while (fi.first != fi.second && *fi.first != feature)
- ++fi.first;
- if (fi.first != fi.second) {
- engine->grFont->getFeatureLabel(fi.first, 0x0409, buf);
+ buf[0] = '\0';
+
+ hb_face_t* hbFace = hb_font_get_face(engine->font->hbFont);
+ gr_face* grFace = hb_graphite2_face_get_gr_face(hbFace);
+
+ if (grFace != NULL) {
+ const gr_feature_ref* feature = gr_face_find_fref(grFace, featureID);
+ for (int i = 0; i < gr_fref_n_values(feature); i++) {
+ if (settingID == gr_fref_value(feature, i)) {
+ uint32_t len = 0;
+ uint16_t langID = 0x409;
+
+ buf = (char*) gr_fref_value_label(feature, i, &langID, gr_utf8, &len);
+
+ if (len > 128 + 1) { // 128 is set in XeTeX_ext.c
+ buf = (char*) realloc(buf, len + 1);
+ buf = (char*) gr_fref_value_label(feature, i, &langID, gr_utf8, &len);
+ }
+
+ buf[len + 1] = '\0';
+ break;
+ }
+ }
}
}
-void getGraphiteFeatureSettingLabel(XeTeXLayoutEngine engine, UInt32 feature, UInt32 setting, unsigned short* buf)
+bool
+findGraphiteFeature(XeTeXLayoutEngine engine, const char* s, const char* e, int* f, int* v)
+ /* s...e is a "feature[=setting]" string; look for this in the font */
{
- buf[0] = 0;
- std::pair<gr::FeatureIterator, gr::FeatureIterator> fi = engine->grFont->getFeatures();
- while (fi.first != fi.second && *fi.first != feature)
- ++fi.first;
- if (fi.first != fi.second) {
- std::pair<gr::FeatureSettingIterator, gr::FeatureSettingIterator>
- si = engine->grFont->getFeatureSettings(fi.first);
- while (si.first != si.second && *si.first != setting)
- ++si.first;
- if (si.first != si.second) {
- engine->grFont->getFeatureSettingLabel(si.first, 0x0409, buf);
- }
- }
+ *f = 0;
+ *v = 0;
+ while (*s == ' ' || *s == '\t')
+ ++s;
+ const char* cp = s;
+ while (cp < e && *cp != '=')
+ ++cp;
+
+ *f = findGraphiteFeatureNamed(engine, s, cp - s);
+ if (*f == -1)
+ return false;
+
+ ++cp;
+ while (cp < e && (*cp == ' ' || *cp == '\t'))
+ ++cp;
+ if (cp >= e)
+ // no setting was specified, so we just use the first
+ // XXX the default is not always the first?
+ return true;
+
+ *v = findGraphiteFeatureSettingNamed(engine, *f, cp, e - cp);
+ if (*v == -1)
+ return false;
+
+ return true;
}
-#endif /* XETEX_GRAPHITE */
long findGraphiteFeatureNamed(XeTeXLayoutEngine engine, const char* name, int namelength)
{
long rval = -1;
-#ifdef XETEX_GRAPHITE
- UErrorCode status = (UErrorCode)0;
-
- std::pair<gr::FeatureIterator,gr::FeatureIterator> features = engine->grFont->getFeatures();
- while (features.first != features.second) {
- gr::utf16 label[128];
- if (engine->grFont->getFeatureLabel(features.first, 0x409, &label[0])) {
- UText* ut1 = utext_openUTF8(NULL, name, namelength, &status);
- UText* ut2 = utext_openUChars(NULL, (const UChar*)&label[0], -1, &status);
- UChar32 ch1 = 0, ch2 = 0;
- while (ch1 != U_SENTINEL) {
- ch1 = utext_next32(ut1);
- ch2 = utext_next32(ut2);
- if (ch1 != ch2)
- break;
- }
- ut1 = utext_close(ut1);
- ut2 = utext_close(ut2);
- if (ch1 == ch2) {
- rval = *features.first;
+ hb_face_t* hbFace = hb_font_get_face(engine->font->hbFont);
+ gr_face* grFace = hb_graphite2_face_get_gr_face(hbFace);
+
+ if (grFace != NULL) {
+ for (int i = 0; i < gr_face_n_fref(grFace); i++) {
+ const gr_feature_ref* feature = gr_face_fref(grFace, i);
+ uint32_t len = 0;
+ uint16_t langID = 0x409;
+
+ // the first call is to get the length of the string
+ gr_fref_label(feature, &langID, gr_utf8, &len);
+ char* label = (char*) xmalloc(len);
+ label = (char*) gr_fref_label(feature, &langID, gr_utf8, &len);
+
+ if (strncmp(label, name, namelength) == 0) {
+ rval = gr_fref_id(feature);
+ gr_label_destroy(label);
break;
}
+
+ gr_label_destroy(label);
}
- ++features.first;
}
-#endif
return rval;
}
-long findGraphiteFeatureSettingNamed(XeTeXLayoutEngine engine, UInt32 feature, const char* name, int namelength)
+long findGraphiteFeatureSettingNamed(XeTeXLayoutEngine engine, UInt32 id, const char* name, int namelength)
{
long rval = -1;
-#ifdef XETEX_GRAPHITE
- UErrorCode status = (UErrorCode)0;
-
- std::pair<gr::FeatureIterator,gr::FeatureIterator> features = engine->grFont->getFeatures();
- while (features.first != features.second) {
- if (*features.first == feature) {
- std::pair<gr::FeatureSettingIterator,gr::FeatureSettingIterator>
- settings = engine->grFont->getFeatureSettings(features.first);
- while (settings.first != settings.second) {
- gr::utf16 label[128];
- if (engine->grFont->getFeatureSettingLabel(settings.first, 0x409, &label[0])) {
- UText* ut1 = utext_openUTF8(NULL, name, namelength, &status);
- UText* ut2 = utext_openUChars(NULL, (const UChar*)&label[0], -1, &status);
- UChar32 ch1 = 0, ch2 = 0;
- while (ch1 != U_SENTINEL) {
- ch1 = utext_next32(ut1);
- ch2 = utext_next32(ut2);
- if (ch1 != ch2)
- break;
- }
- ut1 = utext_close(ut1);
- ut2 = utext_close(ut2);
- if (ch1 == ch2) {
- rval = *settings.first;
- break;
- }
- }
- ++settings.first;
+ hb_face_t* hbFace = hb_font_get_face(engine->font->hbFont);
+ gr_face* grFace = hb_graphite2_face_get_gr_face(hbFace);
+
+ if (grFace != NULL) {
+ const gr_feature_ref* feature = gr_face_find_fref(grFace, id);
+ for (int i = 0; i < gr_fref_n_values(feature); i++) {
+ uint32_t len = 0;
+ uint16_t langID = 0x409;
+
+ // the first call is to get the length of the string
+ gr_fref_value_label(feature, i, &langID, gr_utf8, &len);
+ char* label = (char*) xmalloc(len);
+ label = (char*) gr_fref_value_label(feature, i, &langID, gr_utf8, &len);
+
+ if (strncmp(label, name, namelength) == 0) {
+ rval = gr_fref_value(feature, i);
+ gr_label_destroy(label);
+ break;
}
- break;
+
+ gr_label_destroy(label);
}
- ++features.first;
}
-#endif
return rval;
}
float getGlyphWidth(XeTeXFont font, UInt32 gid)
{
- LEPoint adv;
- ((XeTeXFontInst*)font)->getGlyphAdvance(gid, adv);
- return adv.fX;
+ return ((XeTeXFontInst*)font)->getGlyphWidth(gid);
}
UInt32
@@ -546,131 +551,134 @@ float getEmboldenFactor(XeTeXLayoutEngine engine)
return engine->embolden;
}
-XeTeXLayoutEngine createLayoutEngine(PlatformFontRef fontRef, XeTeXFont font, UInt32 scriptTag, UInt32 languageTag,
- UInt32* addFeatures, SInt32* addParams, UInt32* removeFeatures, UInt32 rgbValue,
+XeTeXLayoutEngine createLayoutEngine(PlatformFontRef fontRef, XeTeXFont font, char* script, char* language,
+ hb_feature_t* features, int nFeatures, char **shapers, UInt32 rgbValue,
float extend, float slant, float embolden)
{
- LEErrorCode status = LE_NO_ERROR;
XeTeXLayoutEngine result = new XeTeXLayoutEngine_rec;
result->fontRef = fontRef;
result->font = (XeTeXFontInst*)font;
- result->scriptTag = scriptTag;
- result->languageTag = languageTag;
- result->addedFeatures = addFeatures;
- result->removedFeatures = removeFeatures;
+ result->script = script;
+ result->language = language;
+ result->features = features;
+ result->shapers = shapers;
+ result->nFeatures = nFeatures;
result->rgbValue = rgbValue;
result->extend = extend;
result->slant = slant;
result->embolden = embolden;
-
-#ifdef XETEX_GRAPHITE
- result->grSegment = NULL;
- result->grSource = NULL;
- result->grFont = NULL;
-#endif
-
- result->layoutEngine = XeTeXOTLayoutEngine::LayoutEngineFactory((XeTeXFontInst*)font, scriptTag, languageTag,
- (LETag*)addFeatures, (le_int32*)addParams, (LETag*)removeFeatures, status);
- if (LE_FAILURE(status) || result->layoutEngine == NULL) {
- delete result;
- return NULL;
- }
+ result->hbBuffer = hb_buffer_create();
return result;
}
void deleteLayoutEngine(XeTeXLayoutEngine engine)
{
- delete engine->layoutEngine;
+ hb_buffer_destroy(engine->hbBuffer);
delete engine->font;
-#ifdef XETEX_GRAPHITE
- delete engine->grSegment;
- delete engine->grSource;
- delete engine->grFont;
-#endif
}
-SInt32 layoutChars(XeTeXLayoutEngine engine, UInt16 chars[], SInt32 offset, SInt32 count, SInt32 max,
- char rightToLeft, float x, float y, SInt32* status)
+int layoutChars(XeTeXLayoutEngine engine, UInt16 chars[], SInt32 offset, SInt32 count, SInt32 max,
+ bool rightToLeft)
{
- LEErrorCode success = (LEErrorCode)*status;
- le_int32 glyphCount = engine->layoutEngine->layoutChars((const LEUnicode*)chars,
- offset, count, max, rightToLeft, x, y, success);
- *status = success;
- return glyphCount;
-}
+ hb_script_t script = HB_SCRIPT_INVALID;
+ hb_language_t language = HB_LANGUAGE_INVALID;
+ hb_direction_t direction = HB_DIRECTION_LTR;
-void getGlyphs(XeTeXLayoutEngine engine, UInt32 glyphs[], SInt32* status)
-{
- LEErrorCode success = (LEErrorCode)*status;
- engine->layoutEngine->getGlyphs((LEGlyphID*)glyphs, success);
- *status = success;
-}
+ if (engine->font->getLayoutDirVertical())
+ direction = HB_DIRECTION_TTB;
+ else if (rightToLeft)
+ direction = HB_DIRECTION_RTL;
-void getGlyphPositions(XeTeXLayoutEngine engine, float positions[], SInt32* status)
-{
- LEErrorCode success = (LEErrorCode)*status;
- engine->layoutEngine->getGlyphPositions(positions, success);
+ if (engine->script != NULL)
+ script = hb_script_from_string(engine->script, -1);
- if (engine->extend != 1.0 || engine->slant != 0.0)
- for (int i = 0; i <= engine->layoutEngine->getGlyphCount(); ++i)
- positions[2*i] = positions[2*i] * engine->extend - positions[2*i+1] * engine->slant;
+ if (engine->language != NULL)
+ language = hb_language_from_string(engine->language, -1);
- *status = success;
-}
+ hb_buffer_reset(engine->hbBuffer);
+ hb_buffer_add_utf16(engine->hbBuffer, chars, max, offset, count);
+ hb_buffer_set_direction(engine->hbBuffer, direction);
+ hb_buffer_set_script(engine->hbBuffer, script);
+ hb_buffer_set_language(engine->hbBuffer, language);
-void getGlyphPosition(XeTeXLayoutEngine engine, SInt32 index, float* x, float* y, SInt32* status)
-{
- LEErrorCode success = (LEErrorCode)*status;
- engine->layoutEngine->getGlyphPosition(index, *x, *y, success);
+ hb_shape_full(engine->font->hbFont, engine->hbBuffer, engine->features, engine->nFeatures, engine->shapers);
+ int glyphCount = hb_buffer_get_length(engine->hbBuffer);
- if (engine->extend != 1.0 || engine->slant != 0.0)
- *x = *x * engine->extend - *y * engine->slant;
+#ifdef DEBUG
+ char buf[1024];
+ unsigned int consumed;
+ hb_buffer_serialize_flags_t flags = HB_BUFFER_SERIALIZE_FLAGS_DEFAULT;
- *status = success;
-}
+ hb_buffer_serialize_glyphs (engine->hbBuffer, 0, glyphCount, buf, sizeof(buf), &consumed, engine->font->hbFont, HB_BUFFER_SERIALIZE_FORMAT_JSON, flags);
+ if (consumed)
+ printf ("buffer glyphs: %s\n", buf);
+#endif
-UInt32 getScriptTag(XeTeXLayoutEngine engine)
-{
- return engine->scriptTag;
+ return glyphCount;
}
-UInt32 getLanguageTag(XeTeXLayoutEngine engine)
+void getGlyphs(XeTeXLayoutEngine engine, UInt32 glyphs[])
{
- return engine->languageTag;
-}
+ int glyphCount = hb_buffer_get_length(engine->hbBuffer);
+ hb_glyph_info_t *hbGlyphs = hb_buffer_get_glyph_infos(engine->hbBuffer, NULL);
-float getPointSize(XeTeXLayoutEngine engine)
-{
- return engine->font->getXPixelsPerEm();
+ for (int i = 0; i < glyphCount; i++)
+ glyphs[i] = hbGlyphs[i].codepoint;
}
-void getAscentAndDescent(XeTeXLayoutEngine engine, float* ascent, float* descent)
+void getGlyphPositions(XeTeXLayoutEngine engine, float positions[])
{
- *ascent = engine->font->getExactAscent();
- *descent = engine->font->getExactDescent();
+ int glyphCount = hb_buffer_get_length(engine->hbBuffer);
+ hb_glyph_position_t *hbPositions = hb_buffer_get_glyph_positions(engine->hbBuffer, NULL);
+
+ int i = 0;
+ float x = 0, y = 0;
+
+ if (engine->font->getLayoutDirVertical()) {
+ x -= hbPositions[0].y_offset / 64.0; // hack to compensate offset of 1st glyph
+ for (i = 0; i < glyphCount; i++) {
+ positions[2*i] = -(x + hbPositions[i].y_offset / 64.0); /* negative is forwards */
+ positions[2*i+1] = (y + hbPositions[i].x_offset / 64.0);
+ x += hbPositions[i].y_advance / 64.0;
+ y += hbPositions[i].x_advance / 64.0;
+ }
+ positions[2*i] = -x;
+ positions[2*i+1] = y;
+ } else {
+ for (i = 0; i < glyphCount; i++) {
+ positions[2*i] = x + hbPositions[i].x_offset / 64.0;
+ positions[2*i+1] = -(y + hbPositions[i].y_offset / 64.0); /* negative is upwards */
+ x += hbPositions[i].x_advance / 64.0;
+ y += hbPositions[i].y_advance / 64.0;
+ }
+ positions[2*i] = x;
+ positions[2*i+1] = -y;
+ }
+
+ if (engine->extend != 1.0 || engine->slant != 0.0)
+ for (int i = 0; i <= glyphCount; ++i)
+ positions[2*i] = positions[2*i] * engine->extend - positions[2*i+1] * engine->slant;
}
-UInt32* getAddedFeatures(XeTeXLayoutEngine engine)
+float getPointSize(XeTeXLayoutEngine engine)
{
- return engine->addedFeatures;
+ return engine->font->getPointSize();
}
-UInt32* getRemovedFeatures(XeTeXLayoutEngine engine)
+void getAscentAndDescent(XeTeXLayoutEngine engine, float* ascent, float* descent)
{
- return engine->removedFeatures;
+ *ascent = engine->font->getAscent();
+ *descent = engine->font->getDescent();
}
int getDefaultDirection(XeTeXLayoutEngine engine)
{
- switch (engine->scriptTag) {
- case kArabic:
- case kSyriac:
- case kThaana:
- case kHebrew:
- return UBIDI_DEFAULT_RTL;
- }
- return UBIDI_DEFAULT_LTR;
+ hb_script_t script = hb_buffer_get_script(engine->hbBuffer);
+ if (hb_script_get_horizontal_direction (script) == HB_DIRECTION_RTL)
+ return UBIDI_DEFAULT_RTL;
+ else
+ return UBIDI_DEFAULT_LTR;
}
UInt32 getRgbValue(XeTeXLayoutEngine engine)
@@ -855,282 +863,101 @@ mapGlyphToIndex(XeTeXLayoutEngine engine, const char* glyphName)
return engine->font->mapGlyphToIndex(glyphName);
}
-#ifdef XETEX_MAC
-/* this is here rather than XeTeX_mac.c because I want it in a .cpp file */
-int
-GetFontCharRange_AAT(ATSUStyle style, int reqFirst)
-{
- ATSUFontID fontID;
- ATSUGetAttribute(style, kATSUFontTag, sizeof(ATSUFontID), &fontID, 0);
-
- ATSFontRef fontRef = FMGetATSFontRefFromFont(fontID);
-
- ByteCount length;
- OSStatus status = ATSFontGetTable(fontRef, kCmap, 0, 0, 0, &length);
- if (status != noErr)
- return 0;
-
- void* table = LE_NEW_ARRAY(char, length);
- status = ATSFontGetTable(fontRef, kCmap, 0, length, table, &length);
- if (status != noErr) {
- free(table);
- return 0;
- }
-
- CMAPMapper* mapper = CMAPMapper::createUnicodeMapper((const CMAPTable *)table);
-
- int ch = 0;
- if (mapper) {
- if (reqFirst)
- while (mapper->unicodeToGlyph(ch) == 0 && ch < 0x10ffff)
- ++ch;
- else {
- ch = 0x10ffff;
- while (mapper->unicodeToGlyph(ch) == 0 && ch > 0)
- --ch;
- }
- delete mapper;
- }
- else {
- LE_DELETE_ARRAY(table);
- }
-
- return ch;
-
- if (reqFirst) {
- int ch = 0;
- while (MapCharToGlyph_AAT(style, ch) == 0 && ch < 0x10ffff)
- ++ch;
- return ch;
- }
- else {
- int ch = 0x10ffff;
- while (MapCharToGlyph_AAT(style, ch) == 0 && ch > 0)
- --ch;
- return ch;
- }
-}
-#endif
-
-#ifdef XETEX_GRAPHITE
+static gr_segment* grSegment = NULL;
+static const gr_slot* grPrevSlot = NULL;
-/* Graphite interface */
-
-gr::LayoutEnvironment layoutEnv;
-
-XeTeXLayoutEngine createGraphiteEngine(PlatformFontRef fontRef, XeTeXFont font,
- const char* name,
- UInt32 rgbValue, int rtl, UInt32 languageTag,
- float extend, float slant, float embolden,
- int nFeatures, const int* featureIDs, const int* featureValues)
+bool
+initGraphiteBreaking(XeTeXLayoutEngine engine, const UniChar* txtPtr, int txtLen)
{
- // check if the font supports graphite, and return NULL if not
- const UInt32 kttiSilf = 0x53696C66; // from GrConstants.h
- if (getFontTablePtr(font, kttiSilf) == NULL)
- return NULL;
-
- XeTeXLayoutEngine result = new XeTeXLayoutEngine_rec;
- result->fontRef = fontRef;
- result->font = (XeTeXFontInst*)font;
- result->scriptTag = 0;
- result->languageTag = languageTag;
- result->addedFeatures = NULL;
- result->removedFeatures = NULL;
- result->rgbValue = rgbValue;
- result->extend = extend;
- result->slant = slant;
- result->embolden = embolden;
- result->layoutEngine = NULL;
+ hb_face_t* hbFace = hb_font_get_face(engine->font->hbFont);
+ gr_face* grFace = hb_graphite2_face_get_gr_face(hbFace);
+ gr_font* grFont = hb_graphite2_font_get_gr_font(engine->font->hbFont);
+ if (grFace != NULL && grFont != NULL) {
+ if (grSegment != NULL) {
+ gr_seg_destroy(grSegment);
+ grSegment = NULL;
+ grPrevSlot = NULL;
+ }
- result->grFont = new XeTeXGrFont(result->font, name);
+ hb_tag_t script = HB_TAG_NONE, lang = HB_TAG_NONE;
- result->grSource = new XeTeXGrTextSource(rtl);
- result->grSource->setFeatures(nFeatures, featureIDs, featureValues);
- if (languageTag != 0)
- result->grSource->setLanguage(languageTag);
+ if (engine->script != NULL)
+ script = hb_tag_from_string(engine->script, -1);
- result->grSegment = NULL;
-
- layoutEnv.setDumbFallback(true);
+ if (engine->language != NULL)
+ lang = hb_tag_from_string(engine->language, -1);
- return result;
-}
+ gr_feature_val *grFeatures = gr_face_featureval_for_lang (grFace, lang);
-int
-makeGraphiteSegment(XeTeXLayoutEngine engine, const UniChar* txtPtr, int txtLen)
-{
- if (engine->grSegment) {
- delete engine->grSegment;
- engine->grSegment = NULL;
- }
-
- engine->grSource->setText(txtPtr, txtLen);
- try {
- engine->grSegment = new gr::RangeSegment(engine->grFont, engine->grSource, &layoutEnv);
- }
- catch (gr::FontException f) {
- fprintf(stderr, "*** makeGraphiteSegment: font error %d, returning 0\n", (int)f.errorCode);
- return 0;
- }
- catch (...) {
- fprintf(stderr, "*** makeGraphiteSegment: segment creation failed, returning 0\n");
- return 0;
- }
+ int nFeatures = engine->nFeatures;
+ hb_feature_t *features = engine->features;
+ while (nFeatures--) {
+ const gr_feature_ref *fref = gr_face_find_fref (grFace, features->tag);
+ if (fref)
+ gr_fref_set_feature_value (fref, features->value, grFeatures);
+ features++;
+ }
- return engine->grSegment->glyphs().second - engine->grSegment->glyphs().first;
-}
+ grSegment = gr_make_seg(grFont, grFace, script, grFeatures, gr_utf16, txtPtr, txtLen, 0);
+ grPrevSlot = gr_seg_first_slot(grSegment);
-void
-getGraphiteGlyphInfo(XeTeXLayoutEngine engine, int index, UInt16* glyphID, float* x, float* y)
-{
- if (engine->grSegment == NULL) {
- *glyphID = 0;
- *x = *y = 0.0;
- return;
+ return true;
}
- gr::GlyphIterator i = engine->grSegment->glyphs().first + index;
- *glyphID = i->glyphID();
- if (engine->extend != 1.0 || engine->slant != 0.0)
- *x = i->origin() * engine->extend + i->yOffset() * engine->slant;
- else
- *x = i->origin();
- *y = - i->yOffset();
-}
-float
-graphiteSegmentWidth(XeTeXLayoutEngine engine)
-{
- if (engine->grSegment == NULL)
- return 0.0;
- //return engine->grSegment->advanceWidth(); // can't use this because it ignores trailing WS
- try {
- return engine->extend * engine->grSegment->getRangeWidth(0, engine->grSource->getLength(), false, false, false);
- }
- catch (gr::FontException f) {
- fprintf(stderr, "*** graphiteSegmentWidth: font error %d, returning 0.0\n", (int)f.errorCode);
- return 0.0;
- }
- catch (...) {
- fprintf(stderr, "*** graphiteSegmentWidth: getRangeWidth failed, returning 0.0\n");
- return 0.0;
- }
+ return false;
}
-/* line-breaking uses its own private textsource and segment, not the engine's ones */
-static XeTeXGrTextSource* lbSource = NULL;
-static gr::Segment* lbSegment = NULL;
-static XeTeXLayoutEngine lbEngine = NULL;
-
-#endif /* XETEX_GRAPHITE */
-
-void
-initGraphiteBreaking(XeTeXLayoutEngine engine, const UniChar* txtPtr, int txtLen)
+int
+findNextGraphiteBreak(void)
{
-#ifdef XETEX_GRAPHITE
- if (lbSource == NULL)
- lbSource = new XeTeXGrTextSource(0);
+ if (grSegment == NULL)
+ return -1;
- if (lbSegment != NULL) {
- delete lbSegment;
- lbSegment = NULL;
- }
+ // XXX: gr_cinfo_base() returns "code unit" index not char index, so this
+ // is broken outside BMP
+ if (grPrevSlot && grPrevSlot != gr_seg_last_slot(grSegment)) {
+ const gr_slot* s;
+ const gr_char_info* ci = NULL;
+ for (s = gr_slot_next_in_segment(grPrevSlot); s != NULL; s = gr_slot_next_in_segment(s)) {
+ int bw;
+
+ ci = gr_seg_cinfo(grSegment, gr_slot_index(s));
+ bw = gr_cinfo_break_weight(ci);
+ if (bw < gr_breakNone && bw >= gr_breakBeforeWord) {
+ grPrevSlot = s;
+ return gr_cinfo_base(ci);
+ }
- lbSource->setText(txtPtr, txtLen);
-
- if (lbEngine != engine) {
- gr::FeatureSetting features[64];
- size_t nFeatures = engine->grSource->getFontFeatures(0, features);
- lbSource->setFeatures(nFeatures, &features[0]);
- lbEngine = engine;
- }
-
- try {
- lbSegment = new gr::RangeSegment(engine->grFont, lbSource, &layoutEnv);
- }
- catch (gr::FontException f) {
- fprintf(stderr, "*** initGraphiteBreaking: font error %d\n", (int)f.errorCode);
- }
- catch (...) {
- fprintf(stderr, "*** initGraphiteBreaking: segment creation failed\n");
- }
-#endif
-}
+ if (bw > gr_breakNone && bw <= gr_breakWord) {
+ grPrevSlot = gr_slot_next_in_segment(s);
+ return gr_cinfo_base(ci) + 1;
+ }
+ }
-int
-findNextGraphiteBreak(int iOffset, int iBrkVal)
-{
-#ifdef XETEX_GRAPHITE
- if (lbSegment == NULL)
+ grPrevSlot = gr_seg_last_slot(grSegment);
+ ci = gr_seg_cinfo(grSegment, gr_slot_after(grPrevSlot));
+ return gr_cinfo_base(ci) + 1;
+ } else {
return -1;
- if (iOffset < lbSource->getLength()) {
- while (++iOffset < lbSource->getLength()) {
- const std::pair<gr::GlyphSetIterator,gr::GlyphSetIterator> gsiPair = lbSegment->charToGlyphs(iOffset);
- const gr::GlyphSetIterator& gsi = gsiPair.first;
- if (gsi == gsiPair.second)
- continue;
- if (gsi->breakweight() < gr::klbNoBreak && gsi->breakweight() >= -(gr::LineBrk)iBrkVal)
- return iOffset;
- if (gsi->breakweight() > gr::klbNoBreak && gsi->breakweight() <= (gr::LineBrk)iBrkVal)
- return iOffset + 1;
- }
- return lbSource->getLength();
}
- else
-#endif
- return -1;
}
int usingGraphite(XeTeXLayoutEngine engine)
{
-#ifdef XETEX_GRAPHITE
- return engine->grFont != NULL;
-#else
return 0;
-#endif
}
int usingOpenType(XeTeXLayoutEngine engine)
{
- return engine->layoutEngine != NULL;
+ return engine->hbBuffer != NULL;
}
-#define kMATHTableTag 0x4D415448 /* 'MATH' */
-
int isOpenTypeMathFont(XeTeXLayoutEngine engine)
{
- if (engine->layoutEngine != NULL) {
- if (engine->font->getFontTable(kMATHTableTag) != NULL)
+ if (usingOpenType(engine)) {
+ if (engine->font->getFontTable(kMATH) != NULL)
return 1;
}
return 0;
}
-int
-findGraphiteFeature(XeTeXLayoutEngine engine, const char* s, const char* e, int* f, int* v)
- /* s...e is a "feature=setting" string; look for this in the font */
-{
- while (*s == ' ' || *s == '\t')
- ++s;
- const char* cp = s;
- while (cp < e && *cp != '=')
- ++cp;
- if (cp == e)
- return 0;
-
- *f = findGraphiteFeatureNamed(engine, s, cp - s);
- if (*f == -1)
- return 0;
-
- ++cp;
- while (cp < e && (*cp == ' ' || *cp == '\t'))
- ++cp;
- if (cp == e)
- return 0;
-
- *v = findGraphiteFeatureSettingNamed(engine, *f, cp, e - cp);
- if (*v == -1)
- return 0;
-
- return 1;
-}
-