generated from napi-rs/package-template
-
-
Notifications
You must be signed in to change notification settings - Fork 96
Align font features #1167
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Brooooooklyn
wants to merge
1
commit into
new-font
Choose a base branch
from
align-font-features
base: new-font
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Align font features #1167
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -479,7 +479,13 @@ void skiac_canvas_get_line_metrics_or_draw_text( | |
| const skiac_font_variation* variations, | ||
| int variations_count, | ||
| int kerning, | ||
| int variant_caps) { | ||
| int variant_caps, | ||
| const skiac_font_feature* features, | ||
| int features_count, | ||
| int font_optical_sizing, | ||
| const char* lang, | ||
| float font_size_adjust, | ||
| int text_rendering) { | ||
| auto font_collection = c_collection->collection; | ||
| auto font_style = SkFontStyle(weight, stretch, (SkFontStyle::Slant)slant); | ||
| auto text_direction = (TextDirection)direction; | ||
|
|
@@ -491,28 +497,101 @@ void skiac_canvas_get_line_metrics_or_draw_text( | |
| families_vec.emplace_back(family); | ||
| } | ||
| text_style.setFontFamilies(families_vec); | ||
| text_style.setFontSize(font_size); | ||
|
|
||
| // Apply font-size-adjust if specified (positive value means apply adjustment) | ||
| float effective_font_size = font_size; | ||
| if (font_size_adjust > 0) { | ||
| // Create a temporary paragraph to get the font's actual x-height | ||
| TextStyle temp_style; | ||
| temp_style.setFontFamilies(families_vec); | ||
| temp_style.setFontSize(font_size); | ||
| temp_style.setFontStyle(font_style); | ||
|
|
||
| ParagraphStyle temp_para_style; | ||
| temp_para_style.setTextStyle(temp_style); | ||
| ParagraphBuilderImpl temp_builder(temp_para_style, font_collection, | ||
| SkUnicodes::ICU::Make()); | ||
| temp_builder.addText("x", 1); // Use 'x' to measure x-height | ||
| auto temp_paragraph = | ||
| static_cast<ParagraphImpl*>(temp_builder.Build().release()); | ||
| temp_paragraph->layout(1000); | ||
|
|
||
| if (temp_paragraph->lineNumber() > 0) { | ||
| auto run = temp_paragraph->run(0); | ||
| auto font = run.font(); | ||
| SkFontMetrics metrics; | ||
| font.getMetrics(&metrics); | ||
|
|
||
| // fXHeight is the height of lowercase 'x', typically negative in Skia | ||
| if (metrics.fXHeight != 0) { | ||
| // Calculate actual aspect ratio: |x-height| / font-size | ||
| float actual_aspect = std::abs(metrics.fXHeight) / font_size; | ||
| // Apply font-size-adjust formula: | ||
| // adjusted_size = (target_aspect / actual_aspect) * font_size | ||
| effective_font_size = (font_size_adjust / actual_aspect) * font_size; | ||
| } | ||
| } | ||
| delete temp_paragraph; | ||
| } | ||
|
|
||
| text_style.setFontSize(effective_font_size); | ||
| text_style.setWordSpacing(world_spacing); | ||
| text_style.setLetterSpacing(letter_spacing); | ||
| text_style.setHeight(1); | ||
| text_style.setFontStyle(font_style); | ||
|
|
||
| std::vector<SkFontArguments::VariationPosition::Coordinate> coords; | ||
|
|
||
| // Track if wght/wdth are already set via fontVariationSettings | ||
| bool has_wght = false; | ||
| bool has_wdth = false; | ||
|
|
||
| // Apply variable font variations if provided | ||
| if (variations && variations_count > 0) { | ||
| coords.reserve(variations_count + 1); | ||
| coords.reserve(variations_count + 2); | ||
| for (int i = 0; i < variations_count; i++) { | ||
| coords.push_back({variations[i].tag, variations[i].value}); | ||
| // Check if user explicitly set wght or wdth | ||
| if (variations[i].tag == SkSetFourByteTag('w', 'g', 'h', 't')) { | ||
| has_wght = true; | ||
| } | ||
| if (variations[i].tag == SkSetFourByteTag('w', 'd', 't', 'h')) { | ||
| has_wdth = true; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Apply font weight as 'wght' variation for variable fonts | ||
| // Only if not already set via fontVariationSettings (explicit settings take | ||
| // precedence) 'wght' tag = 0x77676874 | ||
| if (weight != 400 && !has_wght) { | ||
| coords.push_back( | ||
| {SkSetFourByteTag('w', 'g', 'h', 't'), static_cast<float>(weight)}); | ||
| } | ||
|
|
||
| // Apply font stretch as 'wdth' variation for variable fonts | ||
| // 'wdth' tag = 0x77647468 | ||
| if (stretch_width != 100.0f) { | ||
| // Only if not already set via fontVariationSettings (explicit settings take | ||
| // precedence) 'wdth' tag = 0x77647468 | ||
| if (stretch_width != 100.0f && !has_wdth) { | ||
| coords.push_back({SkSetFourByteTag('w', 'd', 't', 'h'), stretch_width}); | ||
| } | ||
|
|
||
| // Apply font optical sizing ('opsz' axis) | ||
| // font_optical_sizing: 0=auto (set to font_size), 1=none (don't set) | ||
| if (font_optical_sizing == 0) { | ||
| // Check if opsz is already set via fontVariationSettings | ||
| bool has_opsz = false; | ||
| for (const auto& coord : coords) { | ||
| if (coord.axis == SkSetFourByteTag('o', 'p', 's', 'z')) { | ||
| has_opsz = true; | ||
| break; | ||
| } | ||
| } | ||
| if (!has_opsz) { | ||
| coords.push_back({SkSetFourByteTag('o', 'p', 's', 'z'), font_size}); | ||
| } | ||
| } | ||
|
|
||
| if (!coords.empty()) { | ||
| SkFontArguments font_args; | ||
| font_args.setVariationDesignPosition( | ||
|
|
@@ -528,7 +607,21 @@ void skiac_canvas_get_line_metrics_or_draw_text( | |
| text_style.addFontFeature(SkString("kern"), 1); | ||
| } | ||
|
|
||
| // TODO: Support fontFeatureSettings | ||
| // Apply fontFeatureSettings (explicit features from the fontFeatureSettings | ||
| // property) These are applied AFTER font-variant-* properties, so they take | ||
| // precedence | ||
| if (features && features_count > 0) { | ||
| for (int i = 0; i < features_count; i++) { | ||
| uint32_t tag = features[i].tag; | ||
| // Convert tag to 4-char string | ||
| char tag_str[5] = {static_cast<char>((tag >> 24) & 0xFF), | ||
| static_cast<char>((tag >> 16) & 0xFF), | ||
| static_cast<char>((tag >> 8) & 0xFF), | ||
| static_cast<char>(tag & 0xFF), '\0'}; | ||
| text_style.addFontFeature(SkString(tag_str), features[i].value); | ||
| } | ||
| } | ||
|
|
||
| // Apply font variant caps features | ||
| // variant_caps: 0=normal, 1=small-caps, 2=all-small-caps, 3=petite-caps, | ||
| // 4=all-petite-caps, 5=unicase, 6=titling-caps | ||
|
|
@@ -554,6 +647,38 @@ void skiac_canvas_get_line_metrics_or_draw_text( | |
| text_style.addFontFeature(SkString("titl"), 1); | ||
| } | ||
|
|
||
| // Apply language/locale for language-specific glyph variants | ||
| // lang: BCP-47 language tag (e.g., "en", "tr", "zh-Hans") or | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 按照 Chrome 开发者给出的答复,这里我们不需要兼容 BCP-47 算法,交给底层的 harfbuzz 来处理就好了 |
||
| // nullptr/"inherit" | ||
| if (lang != nullptr && strlen(lang) > 0 && strcmp(lang, "inherit") != 0) { | ||
| text_style.setLocale(SkString(lang)); | ||
|
|
||
| // Turkish locale: disable "fi" ligature | ||
| // In Turkish, the dotless i (ı) is a separate letter, and the fi ligature | ||
| // would incorrectly merge "f" with "i" when it should remain separate. | ||
| // This matches browser behavior per MDN CanvasRenderingContext2D.lang spec. | ||
| if (strncmp(lang, "tr", 2) == 0 && | ||
| (lang[2] == '\0' || lang[2] == '-' || lang[2] == '_')) { | ||
| text_style.addFontFeature(SkString("liga"), 0); | ||
| } | ||
| } | ||
|
|
||
| // Apply textRendering overrides (these take precedence over fontKerning and | ||
| // fontVariantLigatures) text_rendering: 0=auto, 1=optimizeSpeed, | ||
| // 2=optimizeLegibility, 3=geometricPrecision | ||
| if (text_rendering == 1) { | ||
| // optimizeSpeed: disable kerning and ligatures for speed | ||
| text_style.addFontFeature(SkString("kern"), 0); | ||
| text_style.addFontFeature(SkString("liga"), 0); | ||
| text_style.addFontFeature(SkString("clig"), 0); | ||
| } else if (text_rendering == 2 || text_rendering == 3) { | ||
| // optimizeLegibility / geometricPrecision: enable kerning and ligatures | ||
| text_style.addFontFeature(SkString("kern"), 1); | ||
| text_style.addFontFeature(SkString("liga"), 1); | ||
| text_style.addFontFeature(SkString("clig"), 1); | ||
| } | ||
| // auto (0): respect existing fontKerning and fontVariantLigatures settings | ||
|
|
||
| text_style.setForegroundColor(*PAINT_CAST); | ||
| text_style.setTextBaseline(TextBaseline::kAlphabetic); | ||
| StrutStyle struct_style; | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
让我们标识出哪些是目前 canvas 规范中的,哪些是我们实验性的私有方法。