• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "FontFeatureUtils.h"
18 
19 #include "StringPiece.h"
20 
21 namespace minikin {
22 
cleanAndAddDefaultFontFeatures(const MinikinPaint & paint)23 std::vector<hb_feature_t> cleanAndAddDefaultFontFeatures(const MinikinPaint& paint) {
24     std::vector<hb_feature_t> features;
25     // Disable default-on non-required ligature features if letter-spacing
26     // See http://dev.w3.org/csswg/css-text-3/#letter-spacing-property
27     // "When the effective spacing between two characters is not zero (due to
28     // either justification or a non-zero value of letter-spacing), user agents
29     // should not apply optional ligatures."
30     if (fabs(paint.letterSpacing) > 0.03) {
31         static constexpr hb_feature_t no_liga = {HB_TAG('l', 'i', 'g', 'a'), 0, 0, ~0u};
32         static constexpr hb_feature_t no_clig = {HB_TAG('c', 'l', 'i', 'g'), 0, 0, ~0u};
33         features.push_back(no_liga);
34         features.push_back(no_clig);
35     }
36 
37     bool default_enable_chws = true;
38 
39     static constexpr hb_tag_t chws_tag = HB_TAG('c', 'h', 'w', 's');
40     static constexpr hb_tag_t halt_tag = HB_TAG('h', 'a', 'l', 't');
41     static constexpr hb_tag_t palt_tag = HB_TAG('p', 'a', 'l', 't');
42 
43     SplitIterator it(paint.fontFeatureSettings, ',');
44     while (it.hasNext()) {
45         StringPiece featureStr = it.next();
46         static hb_feature_t feature;
47         // We do not allow setting features on ranges. As such, reject any setting that has
48         // non-universal range.
49         if (hb_feature_from_string(featureStr.data(), featureStr.size(), &feature) &&
50             feature.start == 0 && feature.end == (unsigned int)-1) {
51             // OpenType requires disabling default `chws` feature if glyph-width features.
52             // https://docs.microsoft.com/en-us/typography/opentype/spec/features_ae#tag-chws
53             // Here, we follow Chrome's impl: not enabling default `chws` feature if `palt` or
54             // `halt` is enabled.
55             // https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/platform/fonts/shaping/font_features.cc;drc=77a9a09de0688ca449f5333a305ceaf3f36b6daf;l=215
56             if (default_enable_chws &&
57                 (feature.tag == chws_tag ||
58                  (feature.value && (feature.tag == halt_tag || feature.tag == palt_tag)))) {
59                 default_enable_chws = false;
60             }
61 
62             features.push_back(feature);
63         }
64     }
65 
66     if (default_enable_chws) {
67         static constexpr hb_feature_t chws = {chws_tag, 1, 0, ~0u};
68         features.push_back(chws);
69     }
70 
71     return features;
72 }
73 
74 }  // namespace minikin
75