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

Lines changed: 9 additions & 5 deletions
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

Lines changed: 69 additions & 24 deletions
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

Lines changed: 3 additions & 0 deletions
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

Lines changed: 8 additions & 8 deletions
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

Lines changed: 5 additions & 4 deletions
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

Lines changed: 0 additions & 4 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy