<?php

/**
 * Double Colon
 * Compile pseudo element double colon syntax to single colon syntax for backwards compatibility
 * 
 * @before
 *     p::after { content: '!'; }
 * 
 * @after
 *     p:after { content: '!'; }
 * 
 */
CssCrush_Hook::add('rule_preprocess', 'csscrush_doublecolon');
function csscrush_doublecolon($rule)
{
    $rule->selector_raw = preg_replace('!::(after|before|first-letter|first-line)!', ':$1', $rule->selector_raw);
}
<?php

/**
 * RGBA fallback
 * Only works with background shorthand IE < 8 
 * (http://css-tricks.com/2151-rgba-browser-support/)
 * 
 * @before
 *     background: rgba(0,0,0,.5);
 * 
 * @after
 *     background: rgb(0,0,0);
 *     background: rgba(0,0,0,.5);
 */
CssCrush_Hook::add('rule_postalias', 'csscrush_rgba');
function csscrush_rgba(CssCrush_Rule $rule)
{
    $props = array_keys($rule->properties);
    // Determine which properties apply
    $rgba_props = array();
    foreach ($props as $prop) {
        if ($prop === 'background' or strpos($prop, 'color') !== false) {
            $rgba_props[] = $prop;
        }
    }
    if (empty($rgba_props)) {
        return;
    }
    $new_set = array();
    foreach ($rule as $declaration) {
        $is_viable = in_array($declaration->property, $rgba_props);
<?php

/**
 * Fix clip syntax for IE < 8
 * 
 * @before
 *     clip: rect(1px,1px,1px,1px);
 * 
 * @after
 *     clip: rect(1px,1px,1px,1px);
 *     *clip: rect(1px 1px 1px 1px);
 */
CssCrush_Hook::add('rule_postalias', 'csscrush_clip');
function csscrush_clip(CssCrush_Rule $rule)
{
    // Assume it's been dealt with if the property occurs more than once
    if ($rule->propertyCount('clip') !== 1) {
        return;
    }
    $new_set = array();
    foreach ($rule as $declaration) {
        $new_set[] = $declaration;
        if ($declaration->skip or $declaration->property !== 'clip') {
            continue;
        }
        $new_set[] = $rule->createDeclaration('*clip', str_replace(',', ' ', $rule->getDeclarationValue($declaration)));
    }
    $rule->declarations = $new_set;
}
<?php

/**
 * Opacity for IE < 9
 * 
 * @before 
 *     opacity: 0.45;
 * 
 * @after
 *     opacity: 0.45;
 *     -ms-filter: "alpha(opacity=45)";
 *     *filter: alpha(opacity=45);
 *     zoom: 1;
 */
CssCrush_Hook::add('rule_postalias', 'csscrush_opacity');
function csscrush_opacity(CssCrush_Rule $rule)
{
    if ($rule->propertyCount('opacity') < 1) {
        return;
    }
    $new_set = array();
    foreach ($rule as $declaration) {
        $new_set[] = $declaration;
        if ($declaration->skip or $declaration->property != 'opacity') {
            continue;
        }
        $opacity = (double) $declaration->value;
        $opacity = round($opacity * 100);
        if (!$rule->propertyCount('zoom')) {
            // Filters need hasLayout
            $new_set[] = $rule->createDeclaration('zoom', 1);
<?php

/**
 * Hocus Pocus
 * Non-standard composite pseudo classes
 * 
 * @before
 *     a:hocus { color: red; }
 *     a:pocus { color: red; }
 * 
 * @after
 *    a:hover, a:focus { color: red; }
 *    a:hover, a:focus, a:active { color: red; }
 * 
 */
CssCrush_Hook::add('rule_preprocess', 'csscrush_hocuspocus');
function csscrush_hocuspocus($rule)
{
    $adjustments = array('!:hocus([^a-z0-9_-])!' => ':any(:hover,:focus)$1', '!:pocus([^a-z0-9_-])!' => ':any(:hover,:focus,:active)$1');
    $rule->selector_raw = preg_replace(array_keys($adjustments), array_values($adjustments), $rule->selector_raw);
}
<?php

/**
 * Fix min-height in IE 6
 * 
 * @before
 *     min-height: 100px;
 * 
 * @after
 *     min-height: 100px;
 *     _height: 100px;
 */
CssCrush_Hook::add('rule_postalias', 'csscrush_minheight');
function csscrush_minheight(CssCrush_Rule $rule)
{
    if ($rule->propertyCount('min-height') < 1) {
        return;
    }
    $new_set = array();
    foreach ($rule as $declaration) {
        $new_set[] = $declaration;
        if ($declaration->skip or $declaration->property !== 'min-height') {
            continue;
        }
        $new_set[] = $rule->createDeclaration('_height', $declaration->value);
    }
    $rule->declarations = $new_set;
}
<?php

/**
 * HSL shim
 * Converts HSL values into hex code that works in all browsers
 * 
 * @before
 *     color: hsl( 100, 50%, 50% )
 * 
 * @after
 *    color: #6abf40
 */
CssCrush_Hook::add('rule_postalias', 'csscrush_hsl');
function csscrush_hsl(CssCrush_Rule $rule)
{
    foreach ($rule as &$declaration) {
        if (!$declaration->skip and (!empty($declaration->functions) and in_array('hsl', $declaration->functions))) {
            while (preg_match('!hsl(___p\\d+___)!', $declaration->value, $m)) {
                $full_match = $m[0];
                $token = $m[1];
                $hsl = trim($rule->parens[$token], '()');
                $hsl = array_map('trim', explode(',', $hsl));
                $rgb = CssCrush_Color::cssHslToRgb($hsl);
                $hex = CssCrush_Color::rgbToHex($rgb);
                $declaration->value = str_replace($full_match, $hex, $declaration->value);
            }
        }
    }
}
 * IE filter without the cruft
 * 
 * Using ms vendor prefix outputs expanded and quoted syntax for IE > 7
 * Outputs '*' escaped filter property for IE < 8
 * Adds hasLayout via zoom property (required by filter effects)
 * 
 * 
 * @before
 *     -ms-filter: alpha(opacity=50), blur(strength=10);
 * 
 * @after
 *     -ms-filter: "alpha(opacity=50), progid:DXImageTransform.Microsoft.Blur(strength=10)";
 *     *filter: alpha(opacity=50), progid:DXImageTransform.Microsoft.Blur(strength=10);
 *     zoom: 1;
 */
CssCrush_Hook::add('rule_postalias', 'csscrush_filter');
function csscrush_filter(CssCrush_Rule $rule)
{
    if ($rule->propertyCount('-ms-filter') < 1) {
        return;
    }
    $filter_prefix = 'progid:DXImageTransform.Microsoft.';
    $new_set = array();
    foreach ($rule as $declaration) {
        if ($declaration->skip or $declaration->property !== '-ms-filter') {
            $new_set[] = $declaration;
            continue;
        }
        $list = array_map('trim', explode(',', $declaration->value));
        foreach ($list as &$item) {
            if (strpos($item, $filter_prefix) !== 0 and strpos($item, 'alpha') !== 0) {
<?php

/**
 * Simulate inline-block in IE < 8
 * 
 * @before 
 *     display: inline-block;
 * 
 * @after
 *     display: inline-block;
 *     *display: inline;
 *     *zoom: 1;
 */
CssCrush_Hook::add('rule_postalias', 'csscrush_display_inlineblock');
function csscrush_display_inlineblock(CssCrush_Rule $rule)
{
    if ($rule->propertyCount('display') < 1) {
        return;
    }
    $new_set = array();
    foreach ($rule as $declaration) {
        $new_set[] = $declaration;
        $is_display = $declaration->property === 'display';
        if ($declaration->skip or !$is_display or $is_display and $declaration->value !== 'inline-block') {
            continue;
        }
        $new_set[] = $rule->createDeclaration('*display', 'inline');
        $new_set[] = $rule->createDeclaration('*zoom', 1);
    }
    $rule->declarations = $new_set;
}
/**
 * Shim for CSS3 'initial' keyword value
 * (http://www.w3.org/TR/css3-cascade/#initial0)
 * 
 * @before 
 *     opacity: initial;
 *     white-space: initial;
 *     min-height: initial;
 * 
 * @after
 *     opacity: 1;
 *     white-space: normal;
 *     max-height: auto;
 * 
 */
CssCrush_Hook::add('rule_prealias', 'csscrush_initial');
function csscrush_initial(CssCrush_Rule $rule)
{
    static $initialValues = null;
    if (!$initialValues) {
        if (!($initialValues = @parse_ini_file(CssCrush::$location . '/misc/initial-values.ini'))) {
            trigger_error(__METHOD__ . ": Initial keywords file could not be parsed.\n", E_USER_NOTICE);
            return;
        }
    }
    foreach ($rule as &$declaration) {
        if (!$declaration->skip and 'initial' === $declaration->value) {
            if (isset($initialValues[$declaration->property])) {
                $declaration->value = $initialValues[$declaration->property];
            } else {
                // Fallback to 'inherit'