CSS-Minifier-XS

 view release on metacpan or  search on metacpan

XS.xs  view on Meta::CPAN

    if (0 == strncmp(str, "%",    1)) { return 1; }

    /* Nope */
    return 0;
}

/* collapses all of the nodes to their shortest possible representation */
void CssCollapseNodes(Node* curr) {
    bool inMacIeCommentHack = 0;
    bool inFunction = 0;
    while (curr) {
        Node* next = curr->next;
        switch (curr->type) {
            case NODE_WHITESPACE:
                /* collapse to a single whitespace character */
                curr->length = 1;
                break;
            case NODE_BLOCKCOMMENT:
                if (!inMacIeCommentHack && nodeIsMACIECOMMENTHACK(curr)) {
                    /* START of mac/ie hack */
                    CssSetNodeContents(curr, start_ie_hack, strlen(start_ie_hack));
                    curr->can_prune = 0;
                    inMacIeCommentHack = 1;
                }
                else if (inMacIeCommentHack && !nodeIsMACIECOMMENTHACK(curr)) {
                    /* END of mac/ie hack */
                    CssSetNodeContents(curr, end_ie_hack, strlen(end_ie_hack));
                    curr->can_prune = 0;
                    inMacIeCommentHack = 0;
                }
                break;
            case NODE_IDENTIFIER:
            {
                /* if the node doesn't begin with a "zero", nothing to collapse */
                const char* ptr = curr->contents;
                if ( (*ptr != '0') && (*ptr != '.' )) {
                    /* not "0" and not "point-something" */
                    break;
                }
                if ( (*ptr == '.') && (*(ptr+1) != '0') ) {
                    /* "point-something", but not "point-zero" */
                    break;
                }

                /* skip all leading zeros */
                ptr = CssSkipZeroValue(curr->contents);

                /* if we didn't skip anything, no Zeros to collapse */
                if (ptr == curr->contents) {
                    break;
                }

                /* did we skip the entire thing, and thus the Node is "all zeros"? */
                size_t skipped = ptr - curr->contents;
                if (skipped == curr->length) {
                    /* nothing but zeros, so truncate to "0" */
                    CssSetNodeContents(curr, "0", 1);
                    break;
                }

                /* was it a zero percentage? */
                if (*ptr == '%') {
                    /* a zero percentage; truncate to "0%" */
                    CssSetNodeContents(curr, "0%", 2);
                    break;
                }

                /* if all we're left with is a known CSS unit, and we're NOT in
                 * a function (where we have to preserve units), just truncate
                 * to "0"
                 */
                if (!inFunction && CssIsKnownUnit(ptr)) {
                    /* not in a function, and is a zero unit; truncate to "0" */
                    CssSetNodeContents(curr, "0", 1);
                    break;
                }

                /* otherwise, just skip leading zeros, and preserve any unit */
                /* ... do we need to back up one char to find a significant zero? */
                if (*ptr != '.') { ptr --; }
                /* ... if that's not the start of the buffer ... */
                if (ptr != curr->contents) {
                    /* set the buffer to "0 + units", blowing away the earlier bits */
                    size_t len = curr->length - (ptr - curr->contents);
                    CssSetNodeContents(curr, ptr, len);
                }
                break;
            }
            case NODE_SIGIL:
                if (nodeIsCHAR(curr,'(')) { inFunction = 1; }
                if (nodeIsCHAR(curr,')')) { inFunction = 0; }
                break;
            default:
                break;
        }
        curr = next;
    }
}

/* checks to see whether we can prune the given node from the list.
 *
 * THIS is the function that controls the bulk of the minification process.
 */
enum {
    PRUNE_NO,
    PRUNE_PREVIOUS,
    PRUNE_CURRENT,
    PRUNE_NEXT
};
int CssCanPrune(Node* node) {
    Node* prev = node->prev;
    Node* next = node->next;

    /* only if node is prunable */
    if (!node->can_prune)
        return PRUNE_NO;

    switch (node->type) {
        case NODE_EMPTY:
            /* prune empty nodes */
            return PRUNE_CURRENT;
        case NODE_WHITESPACE:
            /* remove whitespace before comment blocks */



( run in 1.942 second using v1.01-cache-2.11-cpan-39bf76dae61 )