Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a21d4f9

Browse files
CatchABusNathanWalker
authored andcommitted
fix(android): Span should accept all font weight types
1 parent e545f58 commit a21d4f9

File tree

6 files changed

+94
-45
lines changed

6 files changed

+94
-45
lines changed

packages/core/ui/styling/font-common.ts

+9-5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { ParsedFont, FontStyleType, FontWeightType, FontVariationSettingsType }
33
import { makeValidator, makeParser } from '../core/properties';
44
import { Trace } from '../../trace';
55

6+
export const FONTS_BASE_PATH = '/fonts/';
7+
68
export abstract class Font implements FontDefinition {
79
public static default = undefined;
810
public readonly fontStyle: FontStyleType;
@@ -14,7 +16,7 @@ export abstract class Font implements FontDefinition {
1416
}
1517

1618
get isBold(): boolean {
17-
return this.fontWeight === FontWeight.SEMI_BOLD || this.fontWeight === FontWeight.BOLD || this.fontWeight === '700' || this.fontWeight === FontWeight.EXTRA_BOLD || this.fontWeight === FontWeight.BLACK;
19+
return isFontWeightBold(this.fontWeight);
1820
}
1921

2022
protected constructor(
@@ -137,15 +139,18 @@ export function parseFontFamily(value: string): Array<string> {
137139
.filter((v) => !!v);
138140
}
139141

142+
export function isFontWeightBold(fontWeight: FontWeightType): boolean {
143+
return fontWeight === FontWeight.SEMI_BOLD || fontWeight === FontWeight.BOLD || fontWeight === '700' || fontWeight === FontWeight.EXTRA_BOLD || fontWeight === FontWeight.BLACK;
144+
}
145+
140146
export namespace genericFontFamilies {
141147
export const serif = 'serif';
142148
export const sansSerif = 'sans-serif';
143149
export const monospace = 'monospace';
144150
export const system = 'system';
145151
}
146152

147-
const styles = new Set();
148-
[FontStyle.NORMAL, FontStyle.ITALIC].forEach((val, i, a) => styles.add(val));
153+
const styles = new Set<string>([FontStyle.NORMAL, FontStyle.ITALIC]);
149154

150155
// http://www.w3schools.com/cssref/pr_font_weight.asp
151156
//- normal(same as 400)
@@ -159,8 +164,7 @@ const styles = new Set();
159164
//- 700(Bold) (API16 -bold)
160165
//- 800(Extra Bold / Ultra Bold) (API16 -bold)
161166
//- 900(Black / Heavy) (API21 -black)
162-
const weights = new Set();
163-
[FontWeight.THIN, FontWeight.EXTRA_LIGHT, FontWeight.LIGHT, FontWeight.NORMAL, '400', FontWeight.MEDIUM, FontWeight.SEMI_BOLD, FontWeight.BOLD, '700', FontWeight.EXTRA_BOLD, FontWeight.BLACK].forEach((val, i, a) => weights.add(val));
167+
const weights = new Set<string>([FontWeight.THIN, FontWeight.EXTRA_LIGHT, FontWeight.LIGHT, FontWeight.NORMAL, '400', FontWeight.MEDIUM, FontWeight.SEMI_BOLD, FontWeight.BOLD, '700', FontWeight.EXTRA_BOLD, FontWeight.BLACK]);
164168

165169
export function parseFont(fontValue: string): ParsedFont {
166170
const result: ParsedFont = {

packages/core/ui/styling/font.android.ts

+69-24
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Font as FontBase, parseFontFamily, genericFontFamilies, FontWeight, FontVariationSettings } from './font-common';
1+
import { Font as FontBase, parseFontFamily, genericFontFamilies, FontWeight, FontVariationSettings, FONTS_BASE_PATH } from './font-common';
22
import { FontStyleType, FontWeightType, FontVariationSettingsType } from './font-interfaces';
33
import { Trace } from '../../trace';
44
import { SDK_VERSION } from '../../utils/constants';
@@ -7,7 +7,6 @@ import { ad } from '../../utils';
77

88
export * from './font-common';
99

10-
const FONTS_BASE_PATH = '/fonts/';
1110
const typefaceCache = new Map<string, android.graphics.Typeface>();
1211
let appAssets: android.content.res.AssetManager;
1312

@@ -66,24 +65,28 @@ function loadFontFromFile(fontFamily: string, font: Font): android.graphics.Type
6665
return null;
6766
}
6867

69-
let result = typefaceCache.get(cacheKey);
70-
// Check for undefined explicitly as null mean we tried to load the font, but failed.
71-
if (result === undefined) {
72-
result = null;
68+
let result: android.graphics.Typeface;
69+
70+
if (typefaceCache.has(cacheKey)) {
71+
result = typefaceCache.get(cacheKey);
72+
} else {
73+
const basePath = fs.path.join(fs.knownFolders.currentApp().path, FONTS_BASE_PATH, fontFamily);
7374

7475
let fontAssetPath: string;
75-
const basePath = fs.path.join(fs.knownFolders.currentApp().path, 'fonts', fontFamily);
76+
7677
if (fs.File.exists(basePath + '.ttf')) {
77-
fontAssetPath = FONTS_BASE_PATH + fontFamily + '.ttf';
78+
fontAssetPath = basePath + '.ttf';
7879
} else if (fs.File.exists(basePath + '.otf')) {
79-
fontAssetPath = FONTS_BASE_PATH + fontFamily + '.otf';
80+
fontAssetPath = basePath + '.otf';
8081
} else if (Trace.isEnabled()) {
82+
fontAssetPath = null;
8183
Trace.write('Could not find font file for ' + fontFamily, Trace.categories.Error, Trace.messageType.error);
8284
}
8385

86+
result = null; // Default
87+
8488
if (fontAssetPath) {
8589
try {
86-
fontAssetPath = fs.path.join(fs.knownFolders.currentApp().path, fontAssetPath);
8790
if (SDK_VERSION >= 26) {
8891
const builder = new android.graphics.Typeface.Builder(fontAssetPath);
8992
if (builder) {
@@ -104,35 +107,48 @@ function loadFontFromFile(fontFamily: string, font: Font): android.graphics.Type
104107
}
105108
}
106109
}
110+
111+
// The value might be null if there has already been an attempt to load the font but failed
107112
typefaceCache.set(cacheKey, result);
108113
}
109114

110115
return result;
111116
}
112117

113118
function createTypeface(font: Font): android.graphics.Typeface {
114-
let fontStyle = 0;
115-
if (font.isBold) {
116-
fontStyle |= android.graphics.Typeface.BOLD;
117-
}
118-
if (font.isItalic) {
119-
fontStyle |= android.graphics.Typeface.ITALIC;
119+
const fontFamilies = parseFontFamily(font.fontFamily);
120+
const fontWeight = font.fontWeight;
121+
const supportsFontWeight = SDK_VERSION > 27;
122+
123+
let result: android.graphics.Typeface;
124+
let fontStyle: number = 0;
125+
// https://stackoverflow.com/questions/19691530/valid-values-for-androidfontfamily-and-what-they-map-to
126+
let fontSuffix: string;
127+
128+
if (supportsFontWeight) {
129+
fontSuffix = '';
130+
} else {
131+
if (font.isBold) {
132+
fontStyle |= android.graphics.Typeface.BOLD;
133+
}
134+
if (font.isItalic) {
135+
fontStyle |= android.graphics.Typeface.ITALIC;
136+
}
137+
138+
fontSuffix = getFontWeightSuffix(fontWeight);
120139
}
121140

122-
//http://stackoverflow.com/questions/19691530/valid-values-for-androidfontfamily-and-what-they-map-to
123-
const fontFamilies = parseFontFamily(font.fontFamily);
124-
let result: android.graphics.Typeface = null;
125141
for (const fontFamily of fontFamilies) {
126142
switch (fontFamily.toLowerCase()) {
127143
case genericFontFamilies.serif:
128-
result = android.graphics.Typeface.create('serif' + getFontWeightSuffix(font.fontWeight), fontStyle);
144+
result = android.graphics.Typeface.create('serif' + fontSuffix, fontStyle);
129145
break;
130146
case genericFontFamilies.sansSerif:
131147
case genericFontFamilies.system:
132-
result = android.graphics.Typeface.create('sans-serif' + getFontWeightSuffix(font.fontWeight), fontStyle);
148+
result = android.graphics.Typeface.create('sans-serif' + fontSuffix, fontStyle);
133149
break;
134150
case genericFontFamilies.monospace:
135-
result = android.graphics.Typeface.create('monospace' + getFontWeightSuffix(font.fontWeight), fontStyle);
151+
result = android.graphics.Typeface.create('monospace' + fontSuffix, fontStyle);
136152
break;
137153
default: {
138154
result = loadFontFromFile(fontFamily, font);
@@ -143,14 +159,19 @@ function createTypeface(font: Font): android.graphics.Typeface {
143159
}
144160
}
145161

162+
// Found the font!
146163
if (result) {
147-
// Found the font!
148164
break;
149165
}
150166
}
151167

152168
if (!result) {
153-
result = android.graphics.Typeface.create('sans-serif' + getFontWeightSuffix(font.fontWeight), fontStyle);
169+
result = android.graphics.Typeface.create('sans-serif' + fontSuffix, fontStyle);
170+
}
171+
172+
// Newer versions can accept a specific font weight number
173+
if (supportsFontWeight) {
174+
result = android.graphics.Typeface.create(result, getFontWeightNumber(fontWeight), font.isItalic);
154175
}
155176

156177
return result;
@@ -184,3 +205,27 @@ function getFontWeightSuffix(fontWeight: FontWeightType): string {
184205
throw new Error(`Invalid font weight: "${fontWeight}"`);
185206
}
186207
}
208+
209+
function getFontWeightNumber(fontWeight: FontWeightType): number {
210+
let value: number;
211+
212+
if (typeof fontWeight === 'number') {
213+
value = fontWeight;
214+
} else {
215+
switch (fontWeight) {
216+
case FontWeight.NORMAL:
217+
case undefined:
218+
case null:
219+
value = 400;
220+
break;
221+
case FontWeight.BOLD:
222+
value = 700;
223+
break;
224+
default:
225+
value = parseInt(fontWeight);
226+
break;
227+
}
228+
}
229+
230+
return value;
231+
}

packages/core/ui/styling/font.d.ts

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { Font as FontBase } from './font-common';
22
export type { FontStyleType, FontWeightType, ParsedFont, FontVariationSettingsType } from './font-interfaces';
33

4+
export const FONTS_BASE_PATH = '/fonts/';
5+
46
export declare class Font extends FontBase {
57
public static default: Font;
68

@@ -56,6 +58,7 @@ export namespace FontVariationSettings {
5658
}
5759

5860
export function parseFont(fontValue: string): ParsedFont;
61+
export function isFontWeightBold(fontWeight: FontWeightType): boolean;
5962

6063
export namespace ios {
6164
export function registerFont(fontFile: string);

packages/core/ui/styling/font.ios.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Font as FontBase, parseFontFamily, FontWeight, FontVariationSettings, fuzzySearch } from './font-common';
1+
import { Font as FontBase, parseFontFamily, FontWeight, FontVariationSettings, fuzzySearch, FONTS_BASE_PATH } from './font-common';
22
import { FontStyleType, FontWeightType, FontVariationSettingsType } from './font-interfaces';
33
import { Trace } from '../../trace';
44
import * as fs from '../../file-system';
@@ -115,10 +115,9 @@ export class Font extends FontBase {
115115
}
116116

117117
function getNativeFontWeight(fontWeight: FontWeightType): number {
118-
if (typeof fontWeight === 'number') {
119-
fontWeight = (fontWeight + '') as any;
120-
}
121-
switch (fontWeight) {
118+
const value = typeof fontWeight === 'number' ? fontWeight + '' : fontWeight;
119+
120+
switch (value) {
122121
case FontWeight.THIN:
123122
return UIFontWeightUltraLight;
124123
case FontWeight.EXTRA_LIGHT:
@@ -148,7 +147,7 @@ function getNativeFontWeight(fontWeight: FontWeightType): number {
148147

149148
export namespace ios {
150149
export function registerFont(fontFile: string) {
151-
let filePath = fs.path.join(fs.knownFolders.currentApp().path, 'fonts', fontFile);
150+
let filePath = fs.path.join(fs.knownFolders.currentApp().path, FONTS_BASE_PATH, fontFile);
152151
if (!fs.File.exists(filePath)) {
153152
filePath = fs.path.join(fs.knownFolders.currentApp().path, fontFile);
154153
}
@@ -179,7 +178,8 @@ function registerFontsInFolder(fontsFolderPath) {
179178
if (fs.Folder.exists(fs.path.join(fontsFolderPath, fileEntity.name))) {
180179
return true;
181180
}
182-
if (fileEntity instanceof fs.File && ((<fs.File>fileEntity).extension === '.ttf' || (<fs.File>fileEntity).extension === '.otf')) {
181+
182+
if (fileEntity instanceof fs.File && (fileEntity.extension === '.ttf' || fileEntity.extension === '.otf')) {
183183
ios.registerFont(fileEntity.name);
184184
}
185185

@@ -189,7 +189,7 @@ function registerFontsInFolder(fontsFolderPath) {
189189

190190
function registerCustomFonts() {
191191
const appDir = fs.knownFolders.currentApp().path;
192-
const fontsDir = fs.path.join(appDir, 'fonts');
192+
const fontsDir = fs.path.join(appDir, FONTS_BASE_PATH);
193193
if (fs.Folder.exists(fontsDir)) {
194194
registerFontsInFolder(fontsDir);
195195
}

packages/core/ui/text-base/index.android.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import { getClosestPropertyValue, maxLinesProperty, textOverflowProperty } from
33
import { ShadowCSSValues } from '../styling/css-shadow';
44

55
// Requires
6-
import { Font } from '../styling/font';
6+
import { Font, isFontWeightBold } from '../styling/font';
77
import { backgroundColorProperty } from '../styling/style-properties';
8-
import { TextBaseCommon, formattedTextProperty, textAlignmentProperty, textDecorationProperty, textProperty, textTransformProperty, textShadowProperty, textStrokeProperty, letterSpacingProperty, whiteSpaceProperty, lineHeightProperty, isBold, resetSymbol } from './text-base-common';
8+
import { TextBaseCommon, formattedTextProperty, textAlignmentProperty, textDecorationProperty, textProperty, textTransformProperty, textShadowProperty, textStrokeProperty, letterSpacingProperty, whiteSpaceProperty, lineHeightProperty, resetSymbol } from './text-base-common';
99
import { Color } from '../../color';
1010
import { colorProperty, fontSizeProperty, fontInternalProperty, paddingLeftProperty, paddingTopProperty, paddingRightProperty, paddingBottomProperty, Length } from '../styling/style-properties';
1111
import { StrokeCSSValues } from '../styling/css-stroke';
@@ -593,10 +593,11 @@ function createSpannableStringBuilder(formattedString: FormattedString, defaultF
593593

594594
function setSpanModifiers(ssb: android.text.SpannableStringBuilder, span: Span, start: number, end: number, defaultFontSize: number): void {
595595
const spanStyle = span.style;
596-
const bold = isBold(spanStyle.fontWeight);
596+
const bold = isFontWeightBold(spanStyle.fontWeight);
597597
const italic = spanStyle.fontStyle === 'italic';
598598
const align = spanStyle.verticalAlignment;
599599

600+
// We set font style using StyleSpan in case the font doesn't support font styles
600601
if (bold && italic) {
601602
ssb.setSpan(new android.text.style.StyleSpan(android.graphics.Typeface.BOLD_ITALIC), start, end, android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
602603
} else if (bold) {
@@ -607,7 +608,7 @@ function setSpanModifiers(ssb: android.text.SpannableStringBuilder, span: Span,
607608

608609
const fontFamily = span.fontFamily;
609610
if (fontFamily) {
610-
const font = new Font(fontFamily, 0, italic ? 'italic' : 'normal', bold ? 'bold' : 'normal', spanStyle.fontScaleInternal, spanStyle.fontVariationSettings);
611+
const font = new Font(fontFamily, 0, spanStyle.fontStyle, spanStyle.fontWeight, spanStyle.fontScaleInternal, spanStyle.fontVariationSettings);
611612
const typeface = font.getAndroidTypeface() || android.graphics.Typeface.create(fontFamily, 0);
612613
const typefaceSpan: android.text.style.TypefaceSpan = new org.nativescript.widgets.CustomTypefaceSpan(fontFamily, typeface);
613614
ssb.setSpan(typefaceSpan, start, end, android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

packages/core/ui/text-base/text-base-common.ts

-4
Original file line numberDiff line numberDiff line change
@@ -224,10 +224,6 @@ export abstract class TextBaseCommon extends View implements TextBaseDefinition
224224

225225
TextBaseCommon.prototype._isSingleLine = false;
226226

227-
export function isBold(fontWeight: FontWeightType): boolean {
228-
return fontWeight === 'bold' || fontWeight === '700' || fontWeight === '800' || fontWeight === '900';
229-
}
230-
231227
export const textProperty = new Property<TextBaseCommon, string>({
232228
name: 'text',
233229
defaultValue: '',

0 commit comments

Comments
 (0)