All files / roosterjs-content-model-dom/lib/formatHandlers/utils parseValueWithUnit.ts

97.67% Statements 42/43
87.1% Branches 27/31
100% Functions 4/4
97.44% Lines 38/39

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 811x     1x   1x               1x 1359x   2497x   1284x 1284x   1284x 1173x 1173x   1173x   1037x 1037x   58x 58x   9x 9x   8x 8x   11x 11x   36x 36x   6x 6x       1284x 32x     1284x       34x   34x 22x     12x   12x 12x   12x         70x       32x    
const MarginValueRegex = /(-?\d+(\.\d+)?)([a-z]+|%)/;
 
// According to https://developer.mozilla.org/en-US/docs/Glossary/CSS_pixel, 1in = 96px
const PixelPerInch = 96;
 
const DefaultRootFontSize = 16;
 
/**
 * Parse unit value with its unit
 * @param value The source value to parse
 * @param currentSizePxOrElement The source element which has this unit value, or current font size (in px) from context.
 * @param resultUnit Unit for result, can be px or pt. @default px
 */
export function parseValueWithUnit(
    value: string = '',
    currentSizePxOrElement?: number | HTMLElement,
    resultUnit: 'px' | 'pt' = 'px'
): number {
    const match = MarginValueRegex.exec(value);
    let result = 0;
 
    if (match) {
        const [_, numStr, __, unit] = match;
        const num = parseFloat(numStr);
 
        switch (unit) {
            case 'px':
                result = num;
                break;
            case 'pt':
                result = ptToPx(num);
                break;
            case 'em':
                result = getFontSize(currentSizePxOrElement) * num;
                break;
            case 'ex':
                result = (getFontSize(currentSizePxOrElement) * num) / 2;
                break;
            case '%':
                result = (getFontSize(currentSizePxOrElement) * num) / 100;
                break;
            case 'in':
                result = num * PixelPerInch;
                break;
            case 'rem':
                result = (getFontSize(currentSizePxOrElement) || DefaultRootFontSize) * num;
                break;
        }
    }
 
    if (result > 0 && resultUnit == 'pt') {
        result = pxToPt(result);
    }
 
    return result;
}
 
function getFontSize(currentSizeOrElement?: number | HTMLElement): number {
    Iif (typeof currentSizeOrElement === 'undefined') {
        return 0;
    } else if (typeof currentSizeOrElement === 'number') {
        return currentSizeOrElement;
    } else {
        const styleInPt =
            currentSizeOrElement.ownerDocument.defaultView?.getComputedStyle(currentSizeOrElement)
                .fontSize ?? '';
        const floatInPt = parseFloat(styleInPt);
        const floatInPx = ptToPx(floatInPt);
 
        return floatInPx;
    }
}
 
function ptToPx(pt: number): number {
    return Math.round((pt * 4000) / 3) / 1000;
}
 
function pxToPt(px: number) {
    return Math.round((px * 3000) / 4) / 1000;
}