mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-26 11:17:04 +08:00
feat(core): support css font-variation-settings (#9995)
This commit is contained in:
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
@interface NativeScriptUtils : NSObject
|
@interface NativeScriptUtils : NSObject
|
||||||
|
|
||||||
+(UIFont*) getSystemFont:(CGFloat)size weight:(UIFontWeight)weight italic:(BOOL)italic symbolicTraits:(CGFloat)symbolicTraits;
|
+(UIFont*) getSystemFont:(CGFloat)size weight:(UIFontWeight)weight italic:(BOOL)italic symbolicTraits:(UIFontDescriptorSymbolicTraits)symbolicTraits;
|
||||||
+(UIFont*) createUIFont:(NSDictionary*)font;
|
+(UIFont*) createUIFont:(NSDictionary*)font;
|
||||||
+(NSMutableAttributedString*)createMutableStringWithDetails:(NSDictionary*)details;
|
+(NSMutableAttributedString*)createMutableStringWithDetails:(NSDictionary*)details;
|
||||||
+(NSMutableAttributedString*)createMutableStringForSpan:(NSString*)text font:(UIFont*)font color:(UIColor*)color backgroundColor:(UIColor*)backgroundColor textDecoration:(NSString*)textDecoration baselineOffset:(CGFloat)baselineOffset;
|
+(NSMutableAttributedString*)createMutableStringForSpan:(NSString*)text font:(UIFont*)font color:(UIColor*)color backgroundColor:(UIColor*)backgroundColor textDecoration:(NSString*)textDecoration baselineOffset:(CGFloat)baselineOffset;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
@implementation NativeScriptUtils
|
@implementation NativeScriptUtils
|
||||||
|
|
||||||
+(UIFont*) getSystemFont:(CGFloat)size weight:(UIFontWeight)weight italic:(BOOL)italic symbolicTraits:(CGFloat)symbolicTraits {
|
+(UIFont*) getSystemFont:(CGFloat)size weight:(UIFontWeight)weight italic:(BOOL)italic symbolicTraits:(UIFontDescriptorSymbolicTraits)symbolicTraits {
|
||||||
UIFont *result = [UIFont systemFontOfSize:size weight:weight];
|
UIFont *result = [UIFont systemFontOfSize:size weight:weight];
|
||||||
if (italic) {
|
if (italic) {
|
||||||
result = [UIFont fontWithDescriptor:[result.fontDescriptor fontDescriptorWithSymbolicTraits:symbolicTraits] size:size];
|
result = [UIFont fontWithDescriptor:[result.fontDescriptor fontDescriptorWithSymbolicTraits:symbolicTraits] size:size];
|
||||||
@ -35,11 +35,11 @@
|
|||||||
} else if ([family.lowercaseString isEqualToString:@"monospace"]) {
|
} else if ([family.lowercaseString isEqualToString:@"monospace"]) {
|
||||||
fontFamily = @"Courier New";
|
fontFamily = @"Courier New";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fontFamily || [fontFamily isEqualToString:@"sans-serif"] || [fontFamily isEqualToString:@"system"]) {
|
if (!fontFamily || [fontFamily isEqualToString:@"sans-serif"] || [fontFamily isEqualToString:@"system"]) {
|
||||||
result = [NativeScriptUtils getSystemFont:size weight:(UIFontWeight)[[font valueForKey:@"fontWeight"] floatValue] italic:[[font valueForKey:@"isItalic"] boolValue] symbolicTraits:symbolicTraits];
|
result = [NativeScriptUtils getSystemFont:size weight:(UIFontWeight)[[font valueForKey:@"fontWeight"] floatValue] italic:[[font valueForKey:@"isItalic"] boolValue] symbolicTraits:symbolicTraits];
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
UIFontDescriptor *descriptor = [UIFontDescriptor fontDescriptorWithFontAttributes:@{
|
UIFontDescriptor *descriptor = [UIFontDescriptor fontDescriptorWithFontAttributes:@{
|
||||||
UIFontDescriptorFamilyAttribute: fontFamily,
|
UIFontDescriptorFamilyAttribute: fontFamily,
|
||||||
UIFontDescriptorTraitsAttribute: fontDescriptorTraits
|
UIFontDescriptorTraitsAttribute: fontDescriptorTraits
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
declare const enum MDCAnimationTimingFunction {
|
declare const enum MDCAnimationTimingFunction {
|
||||||
|
|
||||||
Standard = 0,
|
Standard = 0,
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
declare class NativeScriptUtils extends NSObject {
|
declare class NativeScriptUtils extends NSObject {
|
||||||
|
|
||||||
static alloc(): NativeScriptUtils; // inherited from NSObject
|
static alloc(): NativeScriptUtils; // inherited from NSObject
|
||||||
@ -11,7 +10,7 @@ declare class NativeScriptUtils extends NSObject {
|
|||||||
|
|
||||||
static getImageDataFormatQuality(image: UIImage, format: string, quality: number): NSData;
|
static getImageDataFormatQuality(image: UIImage, format: string, quality: number): NSData;
|
||||||
|
|
||||||
static getSystemFontWeightItalicSymbolicTraits(size: number, weight: number, italic: boolean, symbolicTraits: number): UIFont;
|
static getSystemFontWeightItalicSymbolicTraits(size: number, weight: number, italic: boolean, symbolicTraits: UIFontDescriptorSymbolicTraits): UIFont;
|
||||||
|
|
||||||
static new(): NativeScriptUtils; // inherited from NSObject
|
static new(): NativeScriptUtils; // inherited from NSObject
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ export { Background } from './styling/background';
|
|||||||
export type { CacheMode } from './styling/background';
|
export type { CacheMode } from './styling/background';
|
||||||
export { parseCSSShadow } from './styling/css-shadow';
|
export { parseCSSShadow } from './styling/css-shadow';
|
||||||
export { animationTimingFunctionConverter, timeConverter } from './styling/converters';
|
export { animationTimingFunctionConverter, timeConverter } from './styling/converters';
|
||||||
export { Font, FontStyle, FontWeight } from './styling/font';
|
export { Font, FontStyle, FontWeight, FontVariationSettings } from './styling/font';
|
||||||
export { Style } from './styling/style';
|
export { Style } from './styling/style';
|
||||||
export type { CommonLayoutParams } from './styling/style';
|
export type { CommonLayoutParams } from './styling/style';
|
||||||
export * from './styling/style-properties';
|
export * from './styling/style-properties';
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { Font as FontDefinition } from './font';
|
import { Font as FontDefinition, FontVariationSettings as FontVariationSettingsType } from './font';
|
||||||
import { ParsedFont } from './font-interfaces';
|
import { ParsedFont } from './font-interfaces';
|
||||||
import { makeValidator, makeParser } from '../core/properties';
|
import { makeValidator, makeParser } from '../core/properties';
|
||||||
|
|
||||||
export * from './font-interfaces';
|
export * from './font-interfaces';
|
||||||
|
export { FontVariationSettingsType };
|
||||||
|
|
||||||
export abstract class Font implements FontDefinition {
|
export abstract class Font implements FontDefinition {
|
||||||
public static default = undefined;
|
public static default = undefined;
|
||||||
@ -18,7 +19,7 @@ export abstract class Font implements FontDefinition {
|
|||||||
return this.fontWeight === FontWeight.SEMI_BOLD || this.fontWeight === FontWeight.BOLD || this.fontWeight === '700' || this.fontWeight === FontWeight.EXTRA_BOLD || this.fontWeight === FontWeight.BLACK;
|
return this.fontWeight === FontWeight.SEMI_BOLD || this.fontWeight === FontWeight.BOLD || this.fontWeight === '700' || this.fontWeight === FontWeight.EXTRA_BOLD || this.fontWeight === FontWeight.BLACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected constructor(public readonly fontFamily: string, public readonly fontSize: number, fontStyle?: FontStyleType, fontWeight?: FontWeightType, fontScale?: number) {
|
protected constructor(public readonly fontFamily: string, public readonly fontSize: number, fontStyle?: FontStyleType, fontWeight?: FontWeightType, fontScale?: number, public readonly fontVariationSettings?: FontVariationSettingsType[]) {
|
||||||
this.fontStyle = fontStyle ?? FontStyle.NORMAL;
|
this.fontStyle = fontStyle ?? FontStyle.NORMAL;
|
||||||
this.fontWeight = fontWeight ?? FontWeight.NORMAL;
|
this.fontWeight = fontWeight ?? FontWeight.NORMAL;
|
||||||
this.fontScale = fontScale ?? 1;
|
this.fontScale = fontScale ?? 1;
|
||||||
@ -31,6 +32,7 @@ export abstract class Font implements FontDefinition {
|
|||||||
public abstract withFontWeight(weight: FontWeightType): Font;
|
public abstract withFontWeight(weight: FontWeightType): Font;
|
||||||
public abstract withFontSize(size: number): Font;
|
public abstract withFontSize(size: number): Font;
|
||||||
public abstract withFontScale(scale: number): Font;
|
public abstract withFontScale(scale: number): Font;
|
||||||
|
public abstract withFontVariationSettings(variationSettings: FontVariationSettingsType[] | null): Font;
|
||||||
|
|
||||||
public static equals(value1: Font, value2: Font): boolean {
|
public static equals(value1: Font, value2: Font): boolean {
|
||||||
// both values are falsy
|
// both values are falsy
|
||||||
@ -70,6 +72,50 @@ export namespace FontWeight {
|
|||||||
export const parse = makeParser<FontWeightType>(isValid);
|
export const parse = makeParser<FontWeightType>(isValid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||||
|
export namespace FontVariationSettings {
|
||||||
|
export function parse(fontVariationSettings: string): FontVariationSettingsType[] | null {
|
||||||
|
const allowedValues = ['normal', 'inherit', 'initial', 'revert', 'revert-layer', 'unset'];
|
||||||
|
const lower = fontVariationSettings?.toLowerCase().trim();
|
||||||
|
if (allowedValues.indexOf(lower) !== -1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const chunks = lower.split(',');
|
||||||
|
if (chunks.length) {
|
||||||
|
const parsed: FontVariationSettingsType[] = [];
|
||||||
|
for (const chunk of chunks) {
|
||||||
|
const axisChunks = chunk.trim();
|
||||||
|
if (axisChunks.length === 2) {
|
||||||
|
const axisName = chunk[0].trim();
|
||||||
|
const axisValue = parseFloat(chunk[0]);
|
||||||
|
// See https://drafts.csswg.org/css-fonts/#font-variation-settings-def.
|
||||||
|
// Axis name strings longer or shorter than four characters are invalid.
|
||||||
|
if (!isNaN(axisValue) && axisName.length === 6 && ((axisName.startsWith("'") && axisName.endsWith("'")) || (axisName.startsWith('"') && axisName.endsWith('"')))) {
|
||||||
|
parsed.push({ axis: axisName, value: axisValue });
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid value (font-variation-settings): ' + fontVariationSettings);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid value (font-variation-settings): ' + fontVariationSettings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Invalid value (font-variation-settings): ' + fontVariationSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toString(fontVariationSettings: FontVariationSettingsType[] | null): string | null {
|
||||||
|
if (fontVariationSettings?.length) {
|
||||||
|
return fontVariationSettings.map(({ axis, value }) => `'${axis}' ${value}`).join(', ');
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function parseFontFamily(value: string): Array<string> {
|
export function parseFontFamily(value: string): Array<string> {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return [];
|
return [];
|
||||||
@ -140,3 +186,31 @@ export function parseFont(fontValue: string): ParsedFont {
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kind of hack.
|
||||||
|
* Used to search font variation axis names, since iOS for some reason requires names
|
||||||
|
* but tags are the standards.
|
||||||
|
*/
|
||||||
|
export function fuzzySearch(query: string, dataset: string[]): string[] | null {
|
||||||
|
const q = query ? query.trim().toLowerCase() : '';
|
||||||
|
|
||||||
|
const result: string[] = [];
|
||||||
|
if (!q.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
dataset.forEach((item) => {
|
||||||
|
const s = item.trim().toLowerCase();
|
||||||
|
let n = -1;
|
||||||
|
for (const char of q) {
|
||||||
|
n = s.indexOf(char, n + 1);
|
||||||
|
if (!~n) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.push(item);
|
||||||
|
});
|
||||||
|
|
||||||
|
return result.length ? result : null;
|
||||||
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import { Font as FontBase, parseFontFamily, genericFontFamilies, FontStyleType, FontWeight, FontWeightType } from './font-common';
|
import { Font as FontBase, parseFontFamily, genericFontFamilies, FontStyleType, FontWeight, FontWeightType, FontVariationSettingsType, FontVariationSettings } from './font-common';
|
||||||
import { Trace } from '../../trace';
|
import { Trace } from '../../trace';
|
||||||
import { SDK_VERSION } from '../../utils';
|
import { SDK_VERSION } from '../../utils';
|
||||||
import * as application from '../../application';
|
import * as application from '../../application';
|
||||||
import * as fs from '../../file-system';
|
import * as fs from '../../file-system';
|
||||||
|
import { Trace } from '../../trace';
|
||||||
|
import { ad } from '../../utils';
|
||||||
|
|
||||||
export * from './font-common';
|
export * from './font-common';
|
||||||
|
|
||||||
@ -15,28 +17,32 @@ export class Font extends FontBase {
|
|||||||
|
|
||||||
private _typeface: android.graphics.Typeface;
|
private _typeface: android.graphics.Typeface;
|
||||||
|
|
||||||
constructor(family: string, size: number, style?: FontStyleType, weight?: FontWeightType) {
|
constructor(family: string, size: number, style?: FontStyleType, weight?: FontWeightType, fontVariationSettings?: FontVariationSettingsType[]) {
|
||||||
super(family, size, style, weight, 1);
|
super(family, size, style, weight, 1, fontVariationSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public withFontFamily(family: string): Font {
|
public withFontFamily(family: string): Font {
|
||||||
return new Font(family, this.fontSize, this.fontStyle, this.fontWeight);
|
return new Font(family, this.fontSize, this.fontStyle, this.fontWeight, this.fontVariationSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public withFontStyle(style: FontStyleType): Font {
|
public withFontStyle(style: FontStyleType): Font {
|
||||||
return new Font(this.fontFamily, this.fontSize, style, this.fontWeight);
|
return new Font(this.fontFamily, this.fontSize, style, this.fontWeight, this.fontVariationSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public withFontWeight(weight: FontWeightType): Font {
|
public withFontWeight(weight: FontWeightType): Font {
|
||||||
return new Font(this.fontFamily, this.fontSize, this.fontStyle, weight);
|
return new Font(this.fontFamily, this.fontSize, this.fontStyle, weight, this.fontVariationSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public withFontSize(size: number): Font {
|
public withFontSize(size: number): Font {
|
||||||
return new Font(this.fontFamily, size, this.fontStyle, this.fontWeight);
|
return new Font(this.fontFamily, size, this.fontStyle, this.fontWeight, this.fontVariationSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public withFontScale(scale: number): Font {
|
public withFontScale(scale: number): Font {
|
||||||
return new Font(this.fontFamily, this.fontSize, this.fontStyle, this.fontWeight);
|
return new Font(this.fontFamily, this.fontSize, this.fontStyle, this.fontWeight, this.fontVariationSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public withFontVariationSettings(variationSettings: FontVariationSettingsType[] | null): Font {
|
||||||
|
return new Font(this.fontFamily, this.fontSize, this.fontStyle, this.fontWeight, variationSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getAndroidTypeface(): android.graphics.Typeface {
|
public getAndroidTypeface(): android.graphics.Typeface {
|
||||||
@ -52,13 +58,21 @@ export class Font extends FontBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadFontFromFile(fontFamily: string): android.graphics.Typeface {
|
function computeFontCacheKey(fontFamily: string, font: Font) {
|
||||||
appAssets = appAssets || application.android.context.getAssets();
|
const sep = ':';
|
||||||
|
return [fontFamily, String(FontVariationSettings.toString(font.fontVariationSettings)).replace(/'/g, '').replace(/[\s,]/g, '_')].join(sep);
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadFontFromFile(fontFamily: string, font: Font): android.graphics.Typeface {
|
||||||
|
const apiLevel = android.os.Build.VERSION.SDK_INT;
|
||||||
|
const cacheKey = apiLevel >= 26 ? computeFontCacheKey(fontFamily, font) : fontFamily;
|
||||||
|
|
||||||
|
appAssets = appAssets || (ad.getApplicationContext() as android.content.Context).getAssets();
|
||||||
if (!appAssets) {
|
if (!appAssets) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = typefaceCache.get(fontFamily);
|
let result = typefaceCache.get(cacheKey);
|
||||||
// Check for undefined explicitly as null mean we tried to load the font, but failed.
|
// Check for undefined explicitly as null mean we tried to load the font, but failed.
|
||||||
if (result === undefined) {
|
if (result === undefined) {
|
||||||
result = null;
|
result = null;
|
||||||
@ -69,23 +83,36 @@ function loadFontFromFile(fontFamily: string): android.graphics.Typeface {
|
|||||||
fontAssetPath = FONTS_BASE_PATH + fontFamily + '.ttf';
|
fontAssetPath = FONTS_BASE_PATH + fontFamily + '.ttf';
|
||||||
} else if (fs.File.exists(basePath + '.otf')) {
|
} else if (fs.File.exists(basePath + '.otf')) {
|
||||||
fontAssetPath = FONTS_BASE_PATH + fontFamily + '.otf';
|
fontAssetPath = FONTS_BASE_PATH + fontFamily + '.otf';
|
||||||
} else {
|
} else if (Trace.isEnabled()) {
|
||||||
if (Trace.isEnabled()) {
|
|
||||||
Trace.write('Could not find font file for ' + fontFamily, Trace.categories.Error, Trace.messageType.error);
|
Trace.write('Could not find font file for ' + fontFamily, Trace.categories.Error, Trace.messageType.error);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (fontAssetPath) {
|
if (fontAssetPath) {
|
||||||
try {
|
try {
|
||||||
fontAssetPath = fs.path.join(fs.knownFolders.currentApp().path, fontAssetPath);
|
fontAssetPath = fs.path.join(fs.knownFolders.currentApp().path, fontAssetPath);
|
||||||
|
if (apiLevel >= 26) {
|
||||||
|
const builder = new android.graphics.Typeface.Builder(fontAssetPath);
|
||||||
|
if (builder) {
|
||||||
|
if (font.fontVariationSettings !== undefined) {
|
||||||
|
builder.setFontVariationSettings(font.fontVariationSettings?.length ? FontVariationSettings.toString(font.fontVariationSettings) : '');
|
||||||
|
}
|
||||||
|
result = builder.build();
|
||||||
|
} else {
|
||||||
result = android.graphics.Typeface.createFromFile(fontAssetPath);
|
result = android.graphics.Typeface.createFromFile(fontAssetPath);
|
||||||
|
if (Trace.isEnabled()) {
|
||||||
|
Trace.write('Could not create builder for ' + fontFamily, Trace.categories.Error, Trace.messageType.error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = android.graphics.Typeface.createFromFile(fontAssetPath);
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (Trace.isEnabled()) {
|
if (Trace.isEnabled()) {
|
||||||
Trace.write('Error loading font asset: ' + fontAssetPath, Trace.categories.Error, Trace.messageType.error);
|
Trace.write('Error loading font asset: ' + fontAssetPath, Trace.categories.Error, Trace.messageType.error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
typefaceCache.set(fontFamily, result);
|
typefaceCache.set(cacheKey, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -101,10 +128,10 @@ function createTypeface(font: Font): android.graphics.Typeface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//http://stackoverflow.com/questions/19691530/valid-values-for-androidfontfamily-and-what-they-map-to
|
//http://stackoverflow.com/questions/19691530/valid-values-for-androidfontfamily-and-what-they-map-to
|
||||||
const fonts = parseFontFamily(font.fontFamily);
|
const fontFamilies = parseFontFamily(font.fontFamily);
|
||||||
let result = null;
|
let result: android.graphics.Typeface = null;
|
||||||
for (let i = 0; i < fonts.length; i++) {
|
for (const fontFamily of fontFamilies) {
|
||||||
switch (fonts[i].toLowerCase()) {
|
switch (fontFamily.toLowerCase()) {
|
||||||
case genericFontFamilies.serif:
|
case genericFontFamilies.serif:
|
||||||
result = android.graphics.Typeface.create('serif' + getFontWeightSuffix(font.fontWeight), fontStyle);
|
result = android.graphics.Typeface.create('serif' + getFontWeightSuffix(font.fontWeight), fontStyle);
|
||||||
break;
|
break;
|
||||||
@ -118,13 +145,14 @@ function createTypeface(font: Font): android.graphics.Typeface {
|
|||||||
result = android.graphics.Typeface.create('monospace' + getFontWeightSuffix(font.fontWeight), fontStyle);
|
result = android.graphics.Typeface.create('monospace' + getFontWeightSuffix(font.fontWeight), fontStyle);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default: {
|
||||||
result = loadFontFromFile(fonts[i]);
|
result = loadFontFromFile(fontFamily, font);
|
||||||
if (result && fontStyle) {
|
if (result && fontStyle) {
|
||||||
result = android.graphics.Typeface.create(result, fontStyle);
|
result = android.graphics.Typeface.create(result, fontStyle);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
// Found the font!
|
// Found the font!
|
||||||
|
15
packages/core/ui/styling/font.d.ts
vendored
15
packages/core/ui/styling/font.d.ts
vendored
@ -6,11 +6,12 @@
|
|||||||
public fontWeight: FontWeightType;
|
public fontWeight: FontWeightType;
|
||||||
public fontSize: number;
|
public fontSize: number;
|
||||||
public fontScale: number;
|
public fontScale: number;
|
||||||
|
public fontVariationSettings?: FontVariationSettings[];
|
||||||
|
|
||||||
public isBold: boolean;
|
public isBold: boolean;
|
||||||
public isItalic: boolean;
|
public isItalic: boolean;
|
||||||
|
|
||||||
constructor(family: string, size: number, style?: FontStyleType, weight?: FontWeightType, scale?: number);
|
constructor(family: string, size: number, style?: FontStyleType, weight?: FontWeightType, scale?: number, fontVariationSettings?: FontVariationSettings[]);
|
||||||
|
|
||||||
public getAndroidTypeface(): any /* android.graphics.Typeface */;
|
public getAndroidTypeface(): any /* android.graphics.Typeface */;
|
||||||
public getUIFont(defaultFont: any /* UIFont */): any /* UIFont */;
|
public getUIFont(defaultFont: any /* UIFont */): any /* UIFont */;
|
||||||
@ -20,6 +21,7 @@
|
|||||||
public withFontWeight(weight: FontWeightType): Font;
|
public withFontWeight(weight: FontWeightType): Font;
|
||||||
public withFontSize(size: number): Font;
|
public withFontSize(size: number): Font;
|
||||||
public withFontScale(scale: number): Font;
|
public withFontScale(scale: number): Font;
|
||||||
|
public withFontVariationSettings(variationSettings: FontVariationSettings[] | null): Font;
|
||||||
|
|
||||||
public static equals(value1: Font, value2: Font): boolean;
|
public static equals(value1: Font, value2: Font): boolean;
|
||||||
}
|
}
|
||||||
@ -47,6 +49,16 @@ export namespace FontWeight {
|
|||||||
export function parse(value: string): FontWeightType;
|
export function parse(value: string): FontWeightType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface FontVariationSettings {
|
||||||
|
axis: string;
|
||||||
|
value: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace FontVariationSettings {
|
||||||
|
export function parse(fontVariationSettings: string): FontVariationSettings[] | null;
|
||||||
|
export function toString(fontVariationSettings: FontVariationSettings[] | null): string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ParsedFont {
|
export interface ParsedFont {
|
||||||
fontStyle?: FontStyleType;
|
fontStyle?: FontStyleType;
|
||||||
fontVariant?: string;
|
fontVariant?: string;
|
||||||
@ -54,6 +66,7 @@ export interface ParsedFont {
|
|||||||
lineHeight?: string;
|
lineHeight?: string;
|
||||||
fontSize?: string;
|
fontSize?: string;
|
||||||
fontFamily?: string;
|
fontFamily?: string;
|
||||||
|
fontVariationSettings?: FontVariationSettings[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseFont(fontValue: string): ParsedFont;
|
export function parseFont(fontValue: string): ParsedFont;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Font as FontBase, parseFontFamily, FontStyle, FontWeight, FontStyleType, FontWeightType } from './font-common';
|
import { Font as FontBase, parseFontFamily, FontWeight, FontStyleType, FontWeightType, FontVariationSettingsType, FontVariationSettings } from './font-common';
|
||||||
import { Trace } from '../../trace';
|
import { Trace } from '../../trace';
|
||||||
import * as fs from '../../file-system';
|
import * as fs from '../../file-system';
|
||||||
export * from './font-common';
|
export * from './font-common';
|
||||||
@ -7,6 +7,7 @@ interface FontDescriptor {
|
|||||||
fontFamily: string[];
|
fontFamily: string[];
|
||||||
fontSize: number;
|
fontSize: number;
|
||||||
fontWeight: number;
|
fontWeight: number;
|
||||||
|
fontVariationSettings: FontVariationSettingsType[] | null;
|
||||||
isBold: boolean;
|
isBold: boolean;
|
||||||
isItalic: boolean;
|
isItalic: boolean;
|
||||||
}
|
}
|
||||||
@ -14,9 +15,9 @@ interface FontDescriptor {
|
|||||||
const uiFontCache = new Map<string, UIFont>();
|
const uiFontCache = new Map<string, UIFont>();
|
||||||
|
|
||||||
function computeFontCacheKey(fontDescriptor: FontDescriptor) {
|
function computeFontCacheKey(fontDescriptor: FontDescriptor) {
|
||||||
const { fontFamily, fontSize, fontWeight, isBold, isItalic } = fontDescriptor;
|
const { fontFamily, fontSize, fontWeight, fontVariationSettings, isBold, isItalic } = fontDescriptor;
|
||||||
const sep = ':';
|
const sep = ':';
|
||||||
return fontFamily.join(sep) + sep + fontSize + sep + fontWeight + sep + isBold + sep + isItalic;
|
return [fontFamily.join(sep), fontSize, fontWeight, String(FontVariationSettings.toString(fontVariationSettings)).replace(/'/g, '').replace(/[\s,]/g, '_'), isBold, isItalic].join(sep);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUIFontCached(fontDescriptor: FontDescriptor) {
|
function getUIFontCached(fontDescriptor: FontDescriptor) {
|
||||||
@ -28,7 +29,25 @@ function getUIFontCached(fontDescriptor: FontDescriptor) {
|
|||||||
}
|
}
|
||||||
return uiFontCache.get(cacheKey);
|
return uiFontCache.get(cacheKey);
|
||||||
}
|
}
|
||||||
const uiFont = NativeScriptUtils.createUIFont(fontDescriptor as any);
|
let uiFont = NativeScriptUtils.createUIFont(fontDescriptor as any);
|
||||||
|
if (fontDescriptor.fontVariationSettings?.length) {
|
||||||
|
let font = CGFontCreateWithFontName(uiFont.fontName);
|
||||||
|
const variationAxes: NSArray<NSDictionary<'kCGFontVariationAxisDefaultValue' | 'kCGFontVariationAxisMaxValue' | 'kCGFontVariationAxisMinValue' | 'kCGFontVariationAxisName', string | number>> = CGFontCopyVariationAxes(font);
|
||||||
|
const variationAxesNames: string[] = [];
|
||||||
|
for (const axis of variationAxes) {
|
||||||
|
variationAxesNames.push(String(axis.objectForKey('kCGFontVariationAxisName')));
|
||||||
|
}
|
||||||
|
const variationSettings = {};
|
||||||
|
for (const variationSetting of fontDescriptor.fontVariationSettings) {
|
||||||
|
const axisName = fuzzySearch(variationSetting.axis, variationAxesNames);
|
||||||
|
if (axisName?.length) {
|
||||||
|
variationSettings[axisName[0]] = variationSetting.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
font = CGFontCreateCopyWithVariations(font, variationSettings as any);
|
||||||
|
uiFont = CTFontCreateWithGraphicsFont(font, fontDescriptor.fontSize, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
uiFontCache.set(cacheKey, uiFont);
|
uiFontCache.set(cacheKey, uiFont);
|
||||||
if (Trace.isEnabled()) {
|
if (Trace.isEnabled()) {
|
||||||
Trace.write(`UIFont creation: ${JSON.stringify(fontDescriptor)}, cache size: ${uiFontCache.size}`, Trace.categories.Style, Trace.messageType.info);
|
Trace.write(`UIFont creation: ${JSON.stringify(fontDescriptor)}, cache size: ${uiFontCache.size}`, Trace.categories.Style, Trace.messageType.info);
|
||||||
@ -40,28 +59,32 @@ function getUIFontCached(fontDescriptor: FontDescriptor) {
|
|||||||
export class Font extends FontBase {
|
export class Font extends FontBase {
|
||||||
public static default = new Font(undefined, undefined);
|
public static default = new Font(undefined, undefined);
|
||||||
|
|
||||||
constructor(family: string, size: number, style?: FontStyleType, weight?: FontWeightType, scale?: number) {
|
constructor(family: string, size: number, style?: FontStyleType, weight?: FontWeightType, scale?: number, variationSettings?: FontVariationSettingsType[]) {
|
||||||
super(family, size, style, weight, scale);
|
super(family, size, style, weight, scale, variationSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public withFontFamily(family: string): Font {
|
public withFontFamily(family: string): Font {
|
||||||
return new Font(family, this.fontSize, this.fontStyle, this.fontWeight, this.fontScale);
|
return new Font(family, this.fontSize, this.fontStyle, this.fontWeight, this.fontScale, this.fontVariationSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public withFontStyle(style: FontStyleType): Font {
|
public withFontStyle(style: FontStyleType): Font {
|
||||||
return new Font(this.fontFamily, this.fontSize, style, this.fontWeight, this.fontScale);
|
return new Font(this.fontFamily, this.fontSize, style, this.fontWeight, this.fontScale, this.fontVariationSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public withFontWeight(weight: FontWeightType): Font {
|
public withFontWeight(weight: FontWeightType): Font {
|
||||||
return new Font(this.fontFamily, this.fontSize, this.fontStyle, weight, this.fontScale);
|
return new Font(this.fontFamily, this.fontSize, this.fontStyle, weight, this.fontScale, this.fontVariationSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public withFontSize(size: number): Font {
|
public withFontSize(size: number): Font {
|
||||||
return new Font(this.fontFamily, size, this.fontStyle, this.fontWeight, this.fontScale);
|
return new Font(this.fontFamily, size, this.fontStyle, this.fontWeight, this.fontScale, this.fontVariationSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public withFontScale(scale: number): Font {
|
public withFontScale(scale: number): Font {
|
||||||
return new Font(this.fontFamily, this.fontSize, this.fontStyle, this.fontWeight, scale);
|
return new Font(this.fontFamily, this.fontSize, this.fontStyle, this.fontWeight, scale, this.fontVariationSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public withFontVariationSettings(variationSettings: FontVariationSettingsType[] | null): Font {
|
||||||
|
return new Font(this.fontFamily, this.fontSize, this.fontStyle, this.fontWeight, this.fontScale, variationSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getUIFont(defaultFont: UIFont): UIFont {
|
public getUIFont(defaultFont: UIFont): UIFont {
|
||||||
@ -69,6 +92,7 @@ export class Font extends FontBase {
|
|||||||
fontFamily: parseFontFamily(this.fontFamily),
|
fontFamily: parseFontFamily(this.fontFamily),
|
||||||
fontSize: this.fontSize || defaultFont.pointSize,
|
fontSize: this.fontSize || defaultFont.pointSize,
|
||||||
fontWeight: getNativeFontWeight(this.fontWeight),
|
fontWeight: getNativeFontWeight(this.fontWeight),
|
||||||
|
fontVariationSettings: this.fontVariationSettings,
|
||||||
isBold: this.isBold,
|
isBold: this.isBold,
|
||||||
isItalic: this.isItalic,
|
isItalic: this.isItalic,
|
||||||
});
|
});
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
// Types
|
// Types
|
||||||
import { unsetValue, CssProperty, CssAnimationProperty, ShorthandProperty, InheritedCssProperty, makeValidator, makeParser } from '../core/properties';
|
import { unsetValue, CssProperty, CssAnimationProperty, ShorthandProperty, InheritedCssProperty } from '../core/properties';
|
||||||
import { Style } from '../styling/style';
|
import { Style } from '../styling/style';
|
||||||
import { Transformation, TransformationValue, TransformFunctionsInfo } from '../animation';
|
import { Transformation, TransformationValue, TransformFunctionsInfo } from '../animation';
|
||||||
|
|
||||||
import { Color } from '../../color';
|
import { Color } from '../../color';
|
||||||
import { Font, parseFont, FontStyle, FontWeight } from '../../ui/styling/font';
|
import { Font, parseFont, FontStyle, FontWeight, FontVariationSettings } from '../../ui/styling/font';
|
||||||
import { layout, hasDuplicates } from '../../utils';
|
import { layout, hasDuplicates } from '../../utils';
|
||||||
import { Background } from '../../ui/styling/background';
|
import { Background } from '../../ui/styling/background';
|
||||||
|
|
||||||
@ -1424,6 +1424,23 @@ const fontProperty = new ShorthandProperty<Style, string>({
|
|||||||
});
|
});
|
||||||
fontProperty.register(Style);
|
fontProperty.register(Style);
|
||||||
|
|
||||||
|
export const fontVariationSettingsProperty = new InheritedCssProperty<Style, FontVariationSettings[] | null>({
|
||||||
|
name: 'fontVariationSettings',
|
||||||
|
cssName: 'font-variation-settings',
|
||||||
|
affectsLayout: global.isIOS,
|
||||||
|
valueChanged: (target, oldValue, newValue) => {
|
||||||
|
const currentFont = target.fontInternal || Font.default;
|
||||||
|
if (currentFont.fontVariationSettings !== newValue) {
|
||||||
|
const newFont = currentFont.withFontVariationSettings(newValue);
|
||||||
|
target.fontInternal = Font.equals(Font.default, newFont) ? unsetValue : newFont;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
valueConverter: (value) => {
|
||||||
|
return FontVariationSettings.parse(value);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
fontVariationSettingsProperty.register(Style);
|
||||||
|
|
||||||
export const visibilityProperty = new CssProperty<Style, CoreTypes.VisibilityType>({
|
export const visibilityProperty = new CssProperty<Style, CoreTypes.VisibilityType>({
|
||||||
name: 'visibility',
|
name: 'visibility',
|
||||||
cssName: 'visibility',
|
cssName: 'visibility',
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
declare class NativeScriptUtils extends NSObject {
|
declare class NativeScriptUtils extends NSObject {
|
||||||
|
|
||||||
static alloc(): NativeScriptUtils; // inherited from NSObject
|
static alloc(): NativeScriptUtils; // inherited from NSObject
|
||||||
@ -11,7 +10,7 @@ declare class NativeScriptUtils extends NSObject {
|
|||||||
|
|
||||||
static getImageDataFormatQuality(image: UIImage, format: string, quality: number): NSData;
|
static getImageDataFormatQuality(image: UIImage, format: string, quality: number): NSData;
|
||||||
|
|
||||||
static getSystemFontWeightItalicSymbolicTraits(size: number, weight: number, italic: boolean, symbolicTraits: number): UIFont;
|
static getSystemFontWeightItalicSymbolicTraits(size: number, weight: number, italic: boolean, symbolicTraits: UIFontDescriptorSymbolicTraits): UIFont;
|
||||||
|
|
||||||
static new(): NativeScriptUtils; // inherited from NSObject
|
static new(): NativeScriptUtils; // inherited from NSObject
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user