diff --git a/_future/textlanguageattr/README b/_future/textlanguageattr/README new file mode 100644 index 00000000..f3bb4916 --- /dev/null +++ b/_future/textlanguageattr/README @@ -0,0 +1 @@ +Removed because proper support on OS X doesn't come until 10.9 unless we use a font with an ltag table; none of the fonts I have come with ltag tables (none of the fonts on OS X do, or at least don't come with a sr entry in their ltag table, and OpenType has replaced ltag with what appears to be custom sub-tables of the GPOS and GSUB tables.) diff --git a/_future/textlanguageattr/attrstr_darwin.m b/_future/textlanguageattr/attrstr_darwin.m new file mode 100644 index 00000000..1717d875 --- /dev/null +++ b/_future/textlanguageattr/attrstr_darwin.m @@ -0,0 +1,19 @@ +struct fontParams { + uiDrawFontDescriptor desc; + uint16_t featureTypes[maxFeatures]; + uint16_t featureSelectors[maxFeatures]; + size_t nFeatures; + const char *language; +}; + + + // locale identifiers are specified as BCP 47: https://developer.apple.com/reference/corefoundation/cflocale?language=objc + case uiAttributeLanguage: + // LONGTERM FUTURE when we move to 10.9, switch to using kCTLanguageAttributeName + ensureFontInRange(p, start, end); + adjustFontInRange(p, start, end, ^(struct fontParams *fp) { + fp->language = (const char *) (spec->Value); + }); + break; + + desc = fontdescAppendFeatures(desc, fp->featureTypes, fp->featureSelectors, fp->nFeatures, fp->language); diff --git a/_future/textlanguageattr/attrstr_unix.c b/_future/textlanguageattr/attrstr_unix.c new file mode 100644 index 00000000..47d22b15 --- /dev/null +++ b/_future/textlanguageattr/attrstr_unix.c @@ -0,0 +1,9 @@ + PangoLanguage *lang; + + // language strings are specified as BCP 47: https://developer.gnome.org/pango/1.30/pango-Scripts-and-Languages.html#pango-language-from-string https://www.ietf.org/rfc/rfc3066.txt + case uiAttributeLanguage: + lang = pango_language_from_string((const char *) (spec->Value)); + addattr(p, start, end, + pango_attr_language_new(lang)); + // lang *cannot* be freed + break; diff --git a/_future/textlanguageattr/attrstr_windows.cpp b/_future/textlanguageattr/attrstr_windows.cpp new file mode 100644 index 00000000..f8238c7f --- /dev/null +++ b/_future/textlanguageattr/attrstr_windows.cpp @@ -0,0 +1,10 @@ + WCHAR *localeName; + + // locale names are specified as BCP 47: https://msdn.microsoft.com/en-us/library/windows/desktop/dd373814(v=vs.85).aspx https://www.ietf.org/rfc/rfc4646.txt + case uiAttributeLanguage: + localeName = toUTF16((char *) (spec->Value)); + hr = p->layout->SetLocaleName(localeName, range); + if (hr != S_OK) + logHRESULT(L"error applying locale name attribute", hr); + uiFree(localeName); + break; \ No newline at end of file diff --git a/_future/textlanguageattr/common_attrlist.c b/_future/textlanguageattr/common_attrlist.c new file mode 100644 index 00000000..680a2d09 --- /dev/null +++ b/_future/textlanguageattr/common_attrlist.c @@ -0,0 +1,2 @@ + case uiAttributeLanguage: + return asciiStringsEqualCaseFold((char *) (attr->spec.Value), (char *) (spec->Value)); diff --git a/_future/textlanguageattr/drawtext_example.c b/_future/textlanguageattr/drawtext_example.c new file mode 100644 index 00000000..e006e7e1 --- /dev/null +++ b/_future/textlanguageattr/drawtext_example.c @@ -0,0 +1,27 @@ +before "or any combination of the above" + + // thanks to https://twitter.com/codeman38/status/831924064012886017 + next = "\xD0\xB1\xD0\xB3\xD0\xB4\xD0\xBF\xD1\x82"; + uiAttributedStringAppendUnattributed(attrstr, "multiple languages (compare "); + start = uiAttributedStringLen(attrstr); + end = start + strlen(next); + uiAttributedStringAppendUnattributed(attrstr, next); + spec.Type = uiAttributeItalic; + spec.Value = uiDrawTextItalicItalic; + uiAttributedStringSetAttribute(attrstr, &spec, start, end); + spec.Type = uiAttributeLanguage; + spec.Value = (uintptr_t) "ru"; + uiAttributedStringSetAttribute(attrstr, &spec, start, end); + uiAttributedStringAppendUnattributed(attrstr, " to "); + start = uiAttributedStringLen(attrstr); + end = start + strlen(next); + uiAttributedStringAppendUnattributed(attrstr, next); + spec.Type = uiAttributeItalic; + spec.Value = uiDrawTextItalicItalic; + uiAttributedStringSetAttribute(attrstr, &spec, start, end); + spec.Type = uiAttributeLanguage; + spec.Value = (uintptr_t) "sr"; + uiAttributedStringSetAttribute(attrstr, &spec, start, end); + uiAttributedStringAppendUnattributed(attrstr, " \xE2\x80\x94 may require changing the font)"); + + uiAttributedStringAppendUnattributed(attrstr, ", "); diff --git a/_future/textlanguageattr/fontmatch_darwin.m b/_future/textlanguageattr/fontmatch_darwin.m new file mode 100644 index 00000000..cd4df7a1 --- /dev/null +++ b/_future/textlanguageattr/fontmatch_darwin.m @@ -0,0 +1,112 @@ +// note: this doesn't work for languages; we have to parse the ltag table + +// fortunately features that aren't supported are simply ignored, so we can copy them all in +// LONGTERM FUTURE when we switch to 10.9, the language parameter won't be needed anymore +// LONGTERM FUTURE and on 10.10 we can use OpenType tags directly! +CTFontDescriptorRef fontdescAppendFeatures(CTFontDescriptorRef desc, const uint16_t *types, const uint16_t *selectors, size_t n, const char *language) +{ + CTFontDescriptorRef new; + CFMutableArrayRef outerArray; + CFDictionaryRef innerDict; + CFNumberRef numType, numSelector; + const void *keys[2], *values[2]; + size_t i; + CFArrayRef languages; + CFIndex il, nl; + CFStringRef curlang; + char d[2]; + + outerArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + if (outerArray == NULL) { + // TODO + } + keys[0] = kCTFontFeatureTypeIdentifierKey; + keys[1] = kCTFontFeatureSelectorIdentifierKey; + for (i = 0; i < n; i++) { + numType = CFNumberCreate(NULL, kCFNumberSInt16Type, + (const SInt16 *) (types + i)); + numSelector = CFNumberCreate(NULL, kCFNumberSInt16Type, + (const SInt16 *) (selectors + i)); + values[0] = numType; + values[1] = numSelector; + innerDict = CFDictionaryCreate(NULL, + keys, values, 2, + // TODO are these correct? + &kCFCopyStringDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (innerDict == NULL) { + // TODO + } + CFArrayAppendValue(outerArray, innerDict); + CFRelease(innerDict); + CFRelease(numSelector); + CFRelease(numType); + } + + // now we have to take care of the language + if (language != NULL) { + languages = CTFontDescriptorCopyAttribute(desc, kCTFontLanguagesAttribute); + if (languages != NULL) { + nl = CFArrayGetCount(languages); + d[0] = language[0]; + if (d[0] >= 'A' && d[0] <= 'Z') + d[0] += 'a' - 'A'; + d[1] = language[1]; + if (d[1] >= 'A' && d[1] <= 'Z') + d[1] += 'a' - 'A'; + for (il = 0; il < nl; il++) { + char c[2]; + + curlang = (CFStringRef) CFArrayGetValueAtIndex(languages, il); + // TODO check for failure + CFStringGetBytes(curlang, CFRangeMake(0, 2), + kCFStringEncodingUTF8, 0, false, + (UInt8 *) c, 2, NULL); + if (c[0] >= 'A' && c[0] <= 'Z') + c[0] += 'a' - 'A'; + if (c[1] >= 'A' && c[1] <= 'Z') + c[1] += 'a' - 'A'; + if (c[0] == d[0] && c[1] == d[1]) + break; + } + if (il != nl) { + uint16_t typ; + + typ = kLanguageTagType; + il++; + numType = CFNumberCreate(NULL, kCFNumberSInt16Type, + (const SInt16 *) (&typ)); + numSelector = CFNumberCreate(NULL, kCFNumberCFIndexType, + &il); + values[0] = numType; + values[1] = numSelector; + innerDict = CFDictionaryCreate(NULL, + keys, values, 2, + // TODO are these correct? + &kCFCopyStringDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (innerDict == NULL) { + // TODO + } + CFArrayAppendValue(outerArray, innerDict); + CFRelease(innerDict); + CFRelease(numSelector); + CFRelease(numType); + } + CFRelease(languages); + } + } + + keys[0] = kCTFontFeatureSettingsAttribute; + values[0] = outerArray; + innerDict = CFDictionaryCreate(NULL, + keys, values, 1, + // TODO are these correct? + &kCFCopyStringDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CFRelease(outerArray); + new = CTFontDescriptorCreateCopyWithAttributes(desc, innerDict); + CFRelease(desc); + CFRelease(innerDict); + return new; +} diff --git a/_future/textlanguageattr/ui.h b/_future/textlanguageattr/ui.h new file mode 100644 index 00000000..2c3c9ec7 --- /dev/null +++ b/_future/textlanguageattr/ui.h @@ -0,0 +1,5 @@ +after UnderlineColor, before feature tags + + // TODO document that this will also enable language-specific font features (TODO on DirectWrite too?) + // TODO document that this should be strict BCP 47 form (A-Z, a-z, 0-9, and -) for maximum compatibility + uiAttributeLanguage, // BCP 47 string diff --git a/_future/verticaltext/README b/_future/verticaltext/README index 1bac02e5..7f30a15c 100644 --- a/_future/verticaltext/README +++ b/_future/verticaltext/README @@ -12,3 +12,6 @@ If readded, this will need to be a layout-wide setting, not a per-character sett More links: https://www.w3.org/TR/2012/NOTE-jlreq-20120403/#line-composition https://www.w3.org/TR/REC-CSS2/notes.html + +TODO indicate where in the attributes.c file that block of code should go (or drop it entirely for the reasons listed above) +TODO same for ui.h diff --git a/common/attrlist.c b/common/attrlist.c index 20aaf97f..7ea65fa6 100644 --- a/common/attrlist.c +++ b/common/attrlist.c @@ -342,9 +342,6 @@ static int specsIdentical(struct attr *attr, uiAttributeSpec *spec) attr->spec.G == spec->G && attr->spec.B == spec->B && attr->spec.A == spec->A; - case uiAttributeLanguage: - return asciiStringsEqualCaseFold((char *) (attr->spec.Value), (char *) (spec->Value)); - // TODO // TODO use boolsEqual() on boolean features } // handles the rest diff --git a/darwin/attrstr.m b/darwin/attrstr.m index f4644b37..3e5797b4 100644 --- a/darwin/attrstr.m +++ b/darwin/attrstr.m @@ -74,7 +74,6 @@ struct fontParams { uint16_t featureTypes[maxFeatures]; uint16_t featureSelectors[maxFeatures]; size_t nFeatures; - const char *language; }; static void ensureFontInRange(struct foreachParams *p, size_t start, size_t end) @@ -258,15 +257,6 @@ static int processAttribute(uiAttributedString *s, uiAttributeSpec *spec, size_t if (spec->Value == uiDrawUnderlineColorCustom) CFRelease(color); break; - // locale identifiers are specified as BCP 47: https://developer.apple.com/reference/corefoundation/cflocale?language=objc - case uiAttributeLanguage: - // LONGTERM FUTURE when we move to 10.9, switch to using kCTLanguageAttributeName - ensureFontInRange(p, start, end); - adjustFontInRange(p, start, end, ^(struct fontParams *fp) { - fp->language = (const char *) (spec->Value); - }); - break; - // TODO default: // handle typographic features ap.p = p; @@ -285,7 +275,7 @@ static CTFontRef fontdescToCTFont(struct fontParams *fp) CTFontRef font; desc = fontdescToCTFontDescriptor(&(fp->desc)); - desc = fontdescAppendFeatures(desc, fp->featureTypes, fp->featureSelectors, fp->nFeatures, fp->language); + desc = fontdescAppendFeatures(desc, fp->featureTypes, fp->featureSelectors, fp->nFeatures); font = CTFontCreateWithFontDescriptor(desc, fp->desc.Size, NULL); CFRelease(desc); // TODO correct? return font; diff --git a/darwin/fontmatch.m b/darwin/fontmatch.m index 9acb2edf..0c87a427 100644 --- a/darwin/fontmatch.m +++ b/darwin/fontmatch.m @@ -257,7 +257,7 @@ CTFontDescriptorRef fontdescToCTFontDescriptor(uiDrawFontDescriptor *fd) // fortunately features that aren't supported are simply ignored, so we can copy them all in // LONGTERM FUTURE when we switch to 10.9, the language parameter won't be needed anymore // LONGTERM FUTURE and on 10.10 we can use OpenType tags directly! -CTFontDescriptorRef fontdescAppendFeatures(CTFontDescriptorRef desc, const uint16_t *types, const uint16_t *selectors, size_t n, const char *language) +CTFontDescriptorRef fontdescAppendFeatures(CTFontDescriptorRef desc, const uint16_t *types, const uint16_t *selectors, size_t n) { CTFontDescriptorRef new; CFMutableArrayRef outerArray; @@ -265,10 +265,6 @@ CTFontDescriptorRef fontdescAppendFeatures(CTFontDescriptorRef desc, const uint1 CFNumberRef numType, numSelector; const void *keys[2], *values[2]; size_t i; - CFArrayRef languages; - CFIndex il, nl; - CFStringRef curlang; - char d[2]; outerArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); if (outerArray == NULL) { @@ -297,60 +293,6 @@ CTFontDescriptorRef fontdescAppendFeatures(CTFontDescriptorRef desc, const uint1 CFRelease(numType); } - // now we have to take care of the language - if (language != NULL) { - languages = CTFontDescriptorCopyAttribute(desc, kCTFontLanguagesAttribute); - if (languages != NULL) { - nl = CFArrayGetCount(languages); - d[0] = language[0]; - if (d[0] >= 'A' && d[0] <= 'Z') - d[0] += 'a' - 'A'; - d[1] = language[1]; - if (d[1] >= 'A' && d[1] <= 'Z') - d[1] += 'a' - 'A'; - for (il = 0; il < nl; il++) { - char c[2]; - - curlang = (CFStringRef) CFArrayGetValueAtIndex(languages, il); - // TODO check for failure - CFStringGetBytes(curlang, CFRangeMake(0, 2), - kCFStringEncodingUTF8, 0, false, - (UInt8 *) c, 2, NULL); - if (c[0] >= 'A' && c[0] <= 'Z') - c[0] += 'a' - 'A'; - if (c[1] >= 'A' && c[1] <= 'Z') - c[1] += 'a' - 'A'; - if (c[0] == d[0] && c[1] == d[1]) - break; - } - if (il != nl) { - uint16_t typ; - - typ = kLanguageTagType; - il++; - numType = CFNumberCreate(NULL, kCFNumberSInt16Type, - (const SInt16 *) (&typ)); - numSelector = CFNumberCreate(NULL, kCFNumberCFIndexType, - &il); - values[0] = numType; - values[1] = numSelector; - innerDict = CFDictionaryCreate(NULL, - keys, values, 2, - // TODO are these correct? - &kCFCopyStringDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - if (innerDict == NULL) { - // TODO - } - CFArrayAppendValue(outerArray, innerDict); - CFRelease(innerDict); - CFRelease(numSelector); - CFRelease(numType); - } - CFRelease(languages); - } - } - keys[0] = kCTFontFeatureSettingsAttribute; values[0] = outerArray; innerDict = CFDictionaryCreate(NULL, diff --git a/darwin/uipriv_darwin.h b/darwin/uipriv_darwin.h index 281a4b57..c3de53e2 100644 --- a/darwin/uipriv_darwin.h +++ b/darwin/uipriv_darwin.h @@ -142,7 +142,7 @@ extern void doManualResize(NSWindow *w, NSEvent *initialEvent, uiWindowResizeEdg // fontmatch.m extern CTFontDescriptorRef fontdescToCTFontDescriptor(uiDrawFontDescriptor *fd); -extern CTFontDescriptorRef fontdescAppendFeatures(CTFontDescriptorRef desc, const uint16_t *types, const uint16_t *selectors, size_t n, const char *language); +extern CTFontDescriptorRef fontdescAppendFeatures(CTFontDescriptorRef desc, const uint16_t *types, const uint16_t *selectors, size_t n); extern void fontdescFromCTFontDescriptor(CTFontDescriptorRef ctdesc, uiDrawFontDescriptor *uidesc); // attrstr.m diff --git a/examples/drawtext/attributes.c b/examples/drawtext/attributes.c index b4a697a8..fbcdd797 100644 --- a/examples/drawtext/attributes.c +++ b/examples/drawtext/attributes.c @@ -130,32 +130,6 @@ static void setupAttributedString(void) uiAttributedStringAppendUnattributed(attrstr, ", "); - // thanks to https://twitter.com/codeman38/status/831924064012886017 - next = "\xD0\xB1\xD0\xB3\xD0\xB4\xD0\xBF\xD1\x82"; - uiAttributedStringAppendUnattributed(attrstr, "multiple languages (compare "); - start = uiAttributedStringLen(attrstr); - end = start + strlen(next); - uiAttributedStringAppendUnattributed(attrstr, next); - spec.Type = uiAttributeItalic; - spec.Value = uiDrawTextItalicItalic; - uiAttributedStringSetAttribute(attrstr, &spec, start, end); - spec.Type = uiAttributeLanguage; - spec.Value = (uintptr_t) "ru"; - uiAttributedStringSetAttribute(attrstr, &spec, start, end); - uiAttributedStringAppendUnattributed(attrstr, " to "); - start = uiAttributedStringLen(attrstr); - end = start + strlen(next); - uiAttributedStringAppendUnattributed(attrstr, next); - spec.Type = uiAttributeItalic; - spec.Value = uiDrawTextItalicItalic; - uiAttributedStringSetAttribute(attrstr, &spec, start, end); - spec.Type = uiAttributeLanguage; - spec.Value = (uintptr_t) "sr"; - uiAttributedStringSetAttribute(attrstr, &spec, start, end); - uiAttributedStringAppendUnattributed(attrstr, " \xE2\x80\x94 may require changing the font)"); - - uiAttributedStringAppendUnattributed(attrstr, ", "); - // TODO randomize these ranges better // TODO make some overlap to test that // TODO also change colors to light foreground dark background diff --git a/ui_attrstr.h b/ui_attrstr.h index 3206efe4..0fb4a586 100644 --- a/ui_attrstr.h +++ b/ui_attrstr.h @@ -15,10 +15,6 @@ _UI_ENUM(uiAttribute) { // TODO ensure the color in the case we don't specify it is the text color? uiAttributeUnderlineColor, // enum uiDrawUnderlineColor - // TODO document that this will also enable language-specific font features (TODO on DirectWrite too?) - // TODO document that this should be strict BCP 47 form (A-Z, a-z, 0-9, and -) for maximum compatibility - uiAttributeLanguage, // BCP 47 string - // These attributes represent typographic features. Each feature // is a separate attribute, to make composition easier. The // availability of for each attribute are defined by the font; the diff --git a/unix/attrstr.c b/unix/attrstr.c index cf5bc509..88eabef4 100644 --- a/unix/attrstr.c +++ b/unix/attrstr.c @@ -142,7 +142,6 @@ static int processAttribute(uiAttributedString *s, uiAttributeSpec *spec, size_t struct foreachParams *p = (struct foreachParams *) data; GClosure *closure; PangoUnderline underline; - PangoLanguage *lang; struct otParam op; switch (spec->Type) { @@ -226,14 +225,6 @@ static int processAttribute(uiAttributedString *s, uiAttributeSpec *spec, size_t break; } break; - // language strings are specified as BCP 47: https://developer.gnome.org/pango/1.30/pango-Scripts-and-Languages.html#pango-language-from-string https://www.ietf.org/rfc/rfc3066.txt - case uiAttributeLanguage: - lang = pango_language_from_string((const char *) (spec->Value)); - addattr(p, start, end, - pango_attr_language_new(lang)); - // lang *cannot* be freed - break; - // TODO default: // handle typographic features op.p = p; diff --git a/windows/attrstr.cpp b/windows/attrstr.cpp index d0a4b3cc..ad2fad0e 100644 --- a/windows/attrstr.cpp +++ b/windows/attrstr.cpp @@ -112,7 +112,6 @@ static int processAttribute(uiAttributedString *s, uiAttributeSpec *spec, size_t WCHAR *wfamily; size_t ostart, oend; BOOL hasUnderline; - WCHAR *localeName; struct otParam op; HRESULT hr; @@ -230,15 +229,6 @@ static int processAttribute(uiAttributedString *s, uiAttributeSpec *spec, size_t break; } break; - // locale names are specified as BCP 47: https://msdn.microsoft.com/en-us/library/windows/desktop/dd373814(v=vs.85).aspx https://www.ietf.org/rfc/rfc4646.txt - case uiAttributeLanguage: - localeName = toUTF16((char *) (spec->Value)); - hr = p->layout->SetLocaleName(localeName, range); - if (hr != S_OK) - logHRESULT(L"error applying locale name attribute", hr); - uiFree(localeName); - break; - // TODO default: // handle typographic features op.p = p;