Commit 221250d2 authored by Xiaocheng Hu's avatar Xiaocheng Hu Committed by Commit Bot

Migrate Blink CSS minifier to GRIT

This patch migrates the Blink CSS minifier to GRIT and applies it
whenever GRIT creates a CSS resource. This allows us to minify all
CSS resources in a unified and effortless manner.

As a result, this patch achieves 12k Android binary size reduction:

https://ci.chromium.org/p/chromium/builders/try/android-binary-size/368229

Bug: 1015410
Change-Id: Ief8efe57d26f2e26c3b53523d8c973d1d193d20b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1900259Reviewed-by: default avatarLei Zhang <thestig@chromium.org>
Reviewed-by: default avatarChris Harrelson <chrishtr@chromium.org>
Reviewed-by: default avatarPhilip Rogers <pdr@chromium.org>
Commit-Queue: Xiaocheng Hu <xiaochengh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#713567}
parent 8b59897b
...@@ -553,14 +553,6 @@ grit("resources") { ...@@ -553,14 +553,6 @@ grit("resources") {
"grit/blink_resources.h", "grit/blink_resources.h",
"blink_resources.pak", "blink_resources.pak",
] ]
grit_flags = [
"-E",
"blink_core_output_dir=" +
rebase_path(blink_core_output_dir, root_build_dir),
]
deps = [
"//third_party/blink/renderer/core:make_minimized_css",
]
} }
grit("image_resources") { grit("image_resources") {
......
...@@ -8,40 +8,38 @@ ...@@ -8,40 +8,38 @@
</outputs> </outputs>
<release seq="1"> <release seq="1">
<includes> <includes>
<!-- Certain CSS files are processed through minimize_css.py --> <!-- GRIT minimizes all CSS and Javascript -->
<include name="IDR_UASTYLE_HTML_CSS" file="${cwd}/${blink_core_output_dir}/html.css" type="BINDATA" compress="gzip"/> <include name="IDR_UASTYLE_HTML_CSS" file="../renderer/core/html/resources/html.css" type="BINDATA" compress="gzip"/>
<include name="IDR_UASTYLE_QUIRKS_CSS" file="${cwd}/${blink_core_output_dir}/quirks.css" type="BINDATA" compress="gzip"/> <include name="IDR_UASTYLE_QUIRKS_CSS" file="../renderer/core/html/resources/quirks.css" type="BINDATA" compress="gzip"/>
<include name="IDR_UASTYLE_VIEW_SOURCE_CSS" file="${cwd}/${blink_core_output_dir}/view-source.css" type="BINDATA" compress="gzip"/> <include name="IDR_UASTYLE_VIEW_SOURCE_CSS" file="../renderer/core/css/view-source.css" type="BINDATA" compress="gzip"/>
<include name="IDR_UASTYLE_THEME_CHROMIUM_ANDROID_CSS" file="${cwd}/${blink_core_output_dir}/android.css" type="BINDATA" compress="gzip"/> <include name="IDR_UASTYLE_THEME_CHROMIUM_ANDROID_CSS" file="../renderer/core/html/resources/android.css" type="BINDATA" compress="gzip"/>
<include name="IDR_UASTYLE_FULLSCREEN_ANDROID_CSS" file="${cwd}/${blink_core_output_dir}/fullscreenAndroid.css" type="BINDATA" compress="gzip"/> <include name="IDR_UASTYLE_FULLSCREEN_ANDROID_CSS" file="../renderer/core/css/fullscreenAndroid.css" type="BINDATA" compress="gzip"/>
<include name="IDR_UASTYLE_THEME_CHROMIUM_LINUX_CSS" file="${cwd}/${blink_core_output_dir}/linux.css" type="BINDATA" compress="gzip"/> <include name="IDR_UASTYLE_THEME_CHROMIUM_LINUX_CSS" file="../renderer/core/html/resources/linux.css" type="BINDATA" compress="gzip"/>
<if expr="is_macosx"> <if expr="is_macosx">
<include name="IDR_UASTYLE_THEME_MAC_CSS" file="../renderer/core/html/resources/mac.css" type="BINDATA" compress="gzip"/> <include name="IDR_UASTYLE_THEME_MAC_CSS" file="../renderer/core/html/resources/mac.css" type="BINDATA" compress="gzip"/>
</if> </if>
<include name="IDR_UASTYLE_THEME_INPUT_MULTIPLE_FIELDS_CSS" file="${cwd}/${blink_core_output_dir}/input_multiple_fields.css" type="BINDATA" compress="gzip"/> <include name="IDR_UASTYLE_THEME_INPUT_MULTIPLE_FIELDS_CSS" file="../renderer/core/html/resources/input_multiple_fields.css" type="BINDATA" compress="gzip"/>
<include name="IDR_UASTYLE_THEME_WIN_CSS" file="${cwd}/${blink_core_output_dir}/win.css" type="BINDATA" compress="gzip"/> <include name="IDR_UASTYLE_THEME_WIN_CSS" file="../renderer/core/html/resources/win.css" type="BINDATA" compress="gzip"/>
<include name="IDR_UASTYLE_THEME_WIN_QUIRKS_CSS" file="${cwd}/${blink_core_output_dir}/win_quirks.css" type="BINDATA" compress="gzip"/> <include name="IDR_UASTYLE_THEME_WIN_QUIRKS_CSS" file="../renderer/core/html/resources/win_quirks.css" type="BINDATA" compress="gzip"/>
<!-- TODO(crbug.com/1015410): Use minimized |controls_refresh.css| with relative urls properly revised -->
<include name="IDR_UASTYLE_THEME_CONTROLS_REFRESH_CSS" file="../renderer/core/html/resources/controls_refresh.css" flattenhtml="true" type="BINDATA" compress="gzip"/> <include name="IDR_UASTYLE_THEME_CONTROLS_REFRESH_CSS" file="../renderer/core/html/resources/controls_refresh.css" flattenhtml="true" type="BINDATA" compress="gzip"/>
<include name="IDR_UASTYLE_THEME_FORCED_COLORS_CSS" file="${cwd}/${blink_core_output_dir}/forced_colors.css" type="BINDATA" compress="gzip"/> <include name="IDR_UASTYLE_THEME_FORCED_COLORS_CSS" file="../renderer/core/html/resources/forced_colors.css" type="BINDATA" compress="gzip"/>
<include name="IDR_UASTYLE_SVG_CSS" file="${cwd}/${blink_core_output_dir}/svg.css" type="BINDATA" compress="gzip"/> <include name="IDR_UASTYLE_SVG_CSS" file="../renderer/core/css/svg.css" type="BINDATA" compress="gzip"/>
<include name="IDR_UASTYLE_MATHML_CSS" file="${cwd}/${blink_core_output_dir}/mathml.css" type="BINDATA" compress="gzip"/> <include name="IDR_UASTYLE_MATHML_CSS" file="../renderer/core/css/mathml.css" type="BINDATA" compress="gzip"/>
<include name="IDR_UASTYLE_FULLSCREEN_CSS" file="${cwd}/${blink_core_output_dir}/fullscreen.css" type="BINDATA" compress="gzip"/> <include name="IDR_UASTYLE_FULLSCREEN_CSS" file="../renderer/core/css/fullscreen.css" type="BINDATA" compress="gzip"/>
<include name="IDR_UASTYLE_XHTMLMP_CSS" file="${cwd}/${blink_core_output_dir}/xhtmlmp.css" type="BINDATA" compress="gzip"/> <include name="IDR_UASTYLE_XHTMLMP_CSS" file="../renderer/core/css/xhtmlmp.css" type="BINDATA" compress="gzip"/>
<include name="IDR_UASTYLE_VIEWPORT_ANDROID_CSS" file="${cwd}/${blink_core_output_dir}/viewportAndroid.css" type="BINDATA" compress="gzip"/> <include name="IDR_UASTYLE_VIEWPORT_ANDROID_CSS" file="../renderer/core/css/viewportAndroid.css" type="BINDATA" compress="gzip"/>
<include name="IDR_UASTYLE_VIEWPORT_TELEVISION_CSS" file="${cwd}/${blink_core_output_dir}/viewportTelevision.css" type="BINDATA" compress="gzip"/> <include name="IDR_UASTYLE_VIEWPORT_TELEVISION_CSS" file="../renderer/core/css/viewportTelevision.css" type="BINDATA" compress="gzip"/>
<include name="IDR_INSPECT_TOOL_COMMON_JS" file="../renderer/core/inspector/inspect_tool_common.js" type="BINDATA" compress="gzip"/> <include name="IDR_INSPECT_TOOL_COMMON_JS" file="../renderer/core/inspector/inspect_tool_common.js" type="BINDATA" compress="gzip"/>
<include name="IDR_INSPECT_TOOL_COMMON_CSS" file="${cwd}/${blink_core_output_dir}/inspect_tool_common.css" type="BINDATA" compress="gzip"/> <include name="IDR_INSPECT_TOOL_COMMON_CSS" file="../renderer/core/inspector/inspect_tool_common.css" type="BINDATA" compress="gzip"/>
<include name="IDR_INSPECT_TOOL_DISTANCES_HTML" file="../renderer/core/inspector/inspect_tool_distances.html" type="BINDATA" compress="gzip"/> <include name="IDR_INSPECT_TOOL_DISTANCES_HTML" file="../renderer/core/inspector/inspect_tool_distances.html" type="BINDATA" compress="gzip"/>
<include name="IDR_INSPECT_TOOL_HIGHLIGHT_HTML" file="../renderer/core/inspector/inspect_tool_highlight.html" type="BINDATA" compress="gzip"/> <include name="IDR_INSPECT_TOOL_HIGHLIGHT_HTML" file="../renderer/core/inspector/inspect_tool_highlight.html" type="BINDATA" compress="gzip"/>
<include name="IDR_INSPECT_TOOL_PAUSED_HTML" file="../renderer/core/inspector/inspect_tool_paused.html" type="BINDATA" compress="gzip"/> <include name="IDR_INSPECT_TOOL_PAUSED_HTML" file="../renderer/core/inspector/inspect_tool_paused.html" type="BINDATA" compress="gzip"/>
<include name="IDR_INSPECT_TOOL_VIEWPORT_SIZE_HTML" file="../renderer/core/inspector/inspect_tool_viewport_size.html" type="BINDATA" compress="gzip"/> <include name="IDR_INSPECT_TOOL_VIEWPORT_SIZE_HTML" file="../renderer/core/inspector/inspect_tool_viewport_size.html" type="BINDATA" compress="gzip"/>
<include name="IDR_INSPECT_TOOL_SCREENSHOT_HTML" file="../renderer/core/inspector/inspect_tool_screenshot.html" type="BINDATA" compress="gzip"/> <include name="IDR_INSPECT_TOOL_SCREENSHOT_HTML" file="../renderer/core/inspector/inspect_tool_screenshot.html" type="BINDATA" compress="gzip"/>
<include name="IDR_DOCUMENTXMLTREEVIEWER_CSS" file="${cwd}/${blink_core_output_dir}/DocumentXMLTreeViewer.css" type="BINDATA" compress="gzip"/> <include name="IDR_DOCUMENTXMLTREEVIEWER_CSS" file="../renderer/core/xml/DocumentXMLTreeViewer.css" type="BINDATA" compress="gzip"/>
<include name="IDR_DOCUMENTXMLTREEVIEWER_JS" file="../renderer/core/xml/DocumentXMLTreeViewer.js" type="BINDATA" compress="gzip"/> <include name="IDR_DOCUMENTXMLTREEVIEWER_JS" file="../renderer/core/xml/DocumentXMLTreeViewer.js" type="BINDATA" compress="gzip"/>
<include name="IDR_VALIDATION_BUBBLE_ICON" file="../renderer/core/html/forms/resources/input_alert.svg" type="BINDATA" compress="gzip"/> <include name="IDR_VALIDATION_BUBBLE_ICON" file="../renderer/core/html/forms/resources/input_alert.svg" type="BINDATA" compress="gzip"/>
<include name="IDR_VALIDATION_BUBBLE_CSS" file="${cwd}/${blink_core_output_dir}/validation_bubble.css" type="BINDATA" compress="gzip"/> <include name="IDR_VALIDATION_BUBBLE_CSS" file="../renderer/core/html/forms/resources/validation_bubble.css" type="BINDATA" compress="gzip"/>
<if expr="not is_android"> <if expr="not is_android">
<include name="IDR_PICKER_COMMON_JS" file="../renderer/core/html/forms/resources/pickerCommon.js" type="BINDATA" compress="gzip"/> <include name="IDR_PICKER_COMMON_JS" file="../renderer/core/html/forms/resources/pickerCommon.js" type="BINDATA" compress="gzip"/>
<include name="IDR_PICKER_COMMON_CSS" file="../renderer/core/html/forms/resources/pickerCommon.css" type="BINDATA" compress="gzip"/> <include name="IDR_PICKER_COMMON_CSS" file="../renderer/core/html/forms/resources/pickerCommon.css" type="BINDATA" compress="gzip"/>
...@@ -64,10 +62,8 @@ ...@@ -64,10 +62,8 @@
<include name="IDR_LIST_PICKER_JS" file="../renderer/core/html/forms/resources/listPicker.js" type="BINDATA" compress="gzip"/> <include name="IDR_LIST_PICKER_JS" file="../renderer/core/html/forms/resources/listPicker.js" type="BINDATA" compress="gzip"/>
</if> </if>
<include name="IDR_AUDIO_SPATIALIZATION_COMPOSITE" file="../renderer/platform/audio/resources/Composite.flac" type="BINDATA"/> <include name="IDR_AUDIO_SPATIALIZATION_COMPOSITE" file="../renderer/platform/audio/resources/Composite.flac" type="BINDATA"/>
<!-- Layered API scripts. --> <!-- Layered API scripts. -->
<part file="../renderer/core/script/resources/layered_api/resources.grdp" /> <part file="../renderer/core/script/resources/layered_api/resources.grdp" />
</includes> </includes>
</release> </release>
</grit> </grit>
#!/usr/bin/env python
# Copyright 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import functools
import os.path
import re
import sys
import in_generator
class CSSMinimizer(object):
INITIAL = 0
MAYBE_COMMENT_START = 1
INSIDE_COMMENT = 2
MAYBE_COMMENT_END = 3
INSIDE_SINGLE_QUOTE = 4
INSIDE_SINGLE_QUOTE_ESCAPE = 5
INSIDE_DOUBLE_QUOTE = 6
INSIDE_DOUBLE_QUOTE_ESCAPE = 7
def __init__(self):
self._output = ''
self._codeblock = ''
def flush_codeblock(self):
stripped = re.sub(r"\s+", ' ', self._codeblock)
stripped = re.sub(r";?\s*(?P<op>[{};])\s*", r'\g<op>', stripped)
self._output += stripped
self._codeblock = ''
def parse(self, content):
state = self.INITIAL
for char in content:
if state == self.INITIAL:
if char == '/':
state = self.MAYBE_COMMENT_START
elif char == "'":
self.flush_codeblock()
self._output += char
state = self.INSIDE_SINGLE_QUOTE
elif char == '"':
self.flush_codeblock()
self._output += char
state = self.INSIDE_DOUBLE_QUOTE
else:
self._codeblock += char
elif state == self.MAYBE_COMMENT_START:
if char == '*':
self.flush_codeblock()
state = self.INSIDE_COMMENT
else:
self._codeblock += '/' + char
state = self.INITIAL
elif state == self.INSIDE_COMMENT:
if char == '*':
state = self.MAYBE_COMMENT_END
else:
pass
elif state == self.MAYBE_COMMENT_END:
if char == '/':
state = self.INITIAL
else:
state = self.INSIDE_COMMENT
elif state == self.INSIDE_SINGLE_QUOTE:
if char == '\\':
self._output += char
state = self.INSIDE_SINGLE_QUOTE_ESCAPE
elif char == "'":
self._output += char
state = self.INITIAL
else:
self._output += char
elif state == self.INSIDE_SINGLE_QUOTE_ESCAPE:
self._output += char
state = self.INSIDE_SINGLE_QUOTE
elif state == self.INSIDE_DOUBLE_QUOTE:
if char == '\\':
self._output += char
state = self.INSIDE_DOUBLE_QUOTE_ESCAPE
elif char == '"':
self._output += char
state = self.INITIAL
else:
self._output += char
elif state == self.INSIDE_DOUBLE_QUOTE_ESCAPE:
self._output += char
state = self.INSIDE_DOUBLE_QUOTE
self.flush_codeblock()
self._output = self._output.strip()
return self._output
@classmethod
def minimize_css(cls, content):
minimizer = CSSMinimizer()
return minimizer.parse(content)
class CSSMinimizerWriter(in_generator.GenericWriter):
def __init__(self, in_file_paths):
super(CSSMinimizerWriter, self).__init__(in_file_paths)
self._outputs = {}
for in_file_path in in_file_paths:
out_path = os.path.basename(in_file_path)
self._outputs[out_path] = functools.partial(self.generate_implementation, in_file_path)
def generate_implementation(self, in_file_path):
content = ''
with open(os.path.abspath(in_file_path)) as in_file:
content = in_file.read()
return CSSMinimizer.minimize_css(content)
if __name__ == '__main__':
in_generator.Maker(CSSMinimizerWriter).main(sys.argv)
...@@ -807,61 +807,6 @@ make_qualified_names("make_core_generated_xml_names") { ...@@ -807,61 +807,6 @@ make_qualified_names("make_core_generated_xml_names") {
# One-off scripts -------------------------------------------------------------- # One-off scripts --------------------------------------------------------------
action("make_minimized_css") {
script = "../build/scripts/minimize_css.py"
inputs = [
"css/fullscreen.css",
"css/fullscreenAndroid.css",
"css/mathml.css",
"css/svg.css",
"css/view-source.css",
"css/viewportAndroid.css",
"css/viewportTelevision.css",
"css/xhtmlmp.css",
"html/forms/resources/validation_bubble.css",
"html/resources/android.css",
"html/resources/forced_colors.css",
"html/resources/html.css",
"html/resources/input_multiple_fields.css",
"html/resources/linux.css",
"html/resources/quirks.css",
"html/resources/win.css",
"html/resources/win_quirks.css",
"inspector/inspect_tool_common.css",
"xml/DocumentXMLTreeViewer.css",
]
outputs = [
"$blink_core_output_dir/fullscreen.css",
"$blink_core_output_dir/fullscreenAndroid.css",
"$blink_core_output_dir/mathml.css",
"$blink_core_output_dir/svg.css",
"$blink_core_output_dir/view-source.css",
"$blink_core_output_dir/viewportAndroid.css",
"$blink_core_output_dir/viewportTelevision.css",
"$blink_core_output_dir/xhtmlmp.css",
"$blink_core_output_dir/validation_bubble.css",
"$blink_core_output_dir/android.css",
"$blink_core_output_dir/forced_colors.css",
"$blink_core_output_dir/html.css",
"$blink_core_output_dir/input_multiple_fields.css",
"$blink_core_output_dir/linux.css",
"$blink_core_output_dir/quirks.css",
"$blink_core_output_dir/win.css",
"$blink_core_output_dir/win_quirks.css",
"$blink_core_output_dir/inspect_tool_common.css",
"$blink_core_output_dir/DocumentXMLTreeViewer.css",
]
args = [
"--output_dir",
rel_blink_core_gen_dir,
]
args += rebase_path(inputs, root_build_dir)
deps = make_core_generated_deps
}
action("make_core_generated_html_entity_table") { action("make_core_generated_html_entity_table") {
visibility = [] # Allow re-assignment of list. visibility = [] # Allow re-assignment of list.
visibility = [ ":*" ] visibility = [ ":*" ]
......
...@@ -10,19 +10,27 @@ import subprocess ...@@ -10,19 +10,27 @@ import subprocess
import sys import sys
__js_minifier = None __js_minifier = None
__css_minifier = None
def SetJsMinifier(minifier): def SetJsMinifier(minifier):
global __js_minifier global __js_minifier
__js_minifier = minifier.split() __js_minifier = minifier.split()
def SetCssMinifier(minifier):
global __css_minifier
__css_minifier = minifier.split()
def Minify(source, filename): def Minify(source, filename):
file_type = path.splitext(filename)[1] file_type = path.splitext(filename)[1]
if not file_type == '.js' or not __js_minifier: minifier = None
if file_type == '.js':
minifier = __js_minifier
elif file_type == '.css':
minifier = __css_minifier
if not minifier:
return source return source
p = subprocess.Popen( p = subprocess.Popen(
__js_minifier, minifier,
stdin=subprocess.PIPE, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE) stderr=subprocess.PIPE)
......
...@@ -136,6 +136,12 @@ Options: ...@@ -136,6 +136,12 @@ Options:
minified Javascript to standard output. A non-zero exit minified Javascript to standard output. A non-zero exit
status will be taken as indicating failure. status will be taken as indicating failure.
--css-minifier A command to run the CSS minifier. If not set then CSS won't
be minified. The command should read the original CSS from
standard input, and output the minified CSS to standard
output. A non-zero exit status will be taken as indicating
failure.
--brotli The full path to the brotli executable generated by --brotli The full path to the brotli executable generated by
third_party/brotli/BUILD.gn, required if any entries use third_party/brotli/BUILD.gn, required if any entries use
compress="brotli". compress="brotli".
...@@ -165,13 +171,14 @@ are exported to translation interchange files (e.g. XMB files), etc. ...@@ -165,13 +171,14 @@ are exported to translation interchange files (e.g. XMB files), etc.
write_only_new = False write_only_new = False
depend_on_stamp = False depend_on_stamp = False
js_minifier = None js_minifier = None
css_minifier = None
replace_ellipsis = True replace_ellipsis = True
(own_opts, args) = getopt.getopt( (own_opts, args) = getopt.getopt(
args, 'a:p:o:D:E:f:w:t:', args, 'a:p:o:D:E:f:w:t:',
('depdir=', 'depfile=', 'assert-file-list=', 'help', ('depdir=', 'depfile=', 'assert-file-list=', 'help',
'output-all-resource-defines', 'no-output-all-resource-defines', 'output-all-resource-defines', 'no-output-all-resource-defines',
'no-replace-ellipsis', 'depend-on-stamp', 'js-minifier=', 'no-replace-ellipsis', 'depend-on-stamp', 'js-minifier=',
'write-only-new=', 'whitelist-support', 'brotli=')) 'css-minifier=', 'write-only-new=', 'whitelist-support', 'brotli='))
for (key, val) in own_opts: for (key, val) in own_opts:
if key == '-a': if key == '-a':
assert_output_files.append(val) assert_output_files.append(val)
...@@ -209,6 +216,8 @@ are exported to translation interchange files (e.g. XMB files), etc. ...@@ -209,6 +216,8 @@ are exported to translation interchange files (e.g. XMB files), etc.
depend_on_stamp = True depend_on_stamp = True
elif key == '--js-minifier': elif key == '--js-minifier':
js_minifier = val js_minifier = val
elif key == '--css-minifier':
css_minifier = val
elif key == '--whitelist-support': elif key == '--whitelist-support':
whitelist_support = True whitelist_support = True
elif key == '--brotli': elif key == '--brotli':
...@@ -235,6 +244,9 @@ are exported to translation interchange files (e.g. XMB files), etc. ...@@ -235,6 +244,9 @@ are exported to translation interchange files (e.g. XMB files), etc.
if js_minifier: if js_minifier:
minifier.SetJsMinifier(js_minifier) minifier.SetJsMinifier(js_minifier)
if css_minifier:
minifier.SetCssMinifier(css_minifier)
self.write_only_new = write_only_new self.write_only_new = write_only_new
self.res = grd_reader.Parse(opts.input, self.res = grd_reader.Parse(opts.input,
......
...@@ -226,6 +226,7 @@ if (current_toolchain != host_toolchain) { ...@@ -226,6 +226,7 @@ if (current_toolchain != host_toolchain) {
_strip_resource_files = is_android && is_official_build _strip_resource_files = is_android && is_official_build
_js_minifier = "//tools/grit/minify_with_uglify.py" _js_minifier = "//tools/grit/minify_with_uglify.py"
_css_minifier = "//tools/grit/minimize_css.py"
grit_resource_id_file = "//tools/gritsettings/resource_ids" grit_resource_id_file = "//tools/gritsettings/resource_ids"
grit_info_script = "//tools/grit/grit_info.py" grit_info_script = "//tools/grit/grit_info.py"
...@@ -407,12 +408,16 @@ template("grit") { ...@@ -407,12 +408,16 @@ template("grit") {
} }
if (_strip_resource_files) { if (_strip_resource_files) {
js_minifier_command = rebase_path(_js_minifier, root_build_dir) js_minifier_command = rebase_path(_js_minifier, root_build_dir)
css_minifier_command = rebase_path(_css_minifier, root_build_dir)
args += [ args += [
"--js-minifier", "--js-minifier",
js_minifier_command, js_minifier_command,
"--css-minifier",
css_minifier_command,
] ]
inputs += [ inputs += [
_js_minifier, _js_minifier,
_css_minifier,
"//third_party/closure_compiler/compiler/compiler.jar", "//third_party/closure_compiler/compiler/compiler.jar",
] ]
} }
......
#!/usr/bin/env python
# Copyright 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import re
import sys
class CSSMinimizer(object):
INITIAL = 0
MAYBE_COMMENT_START = 1
INSIDE_COMMENT = 2
MAYBE_COMMENT_END = 3
INSIDE_SINGLE_QUOTE = 4
INSIDE_SINGLE_QUOTE_ESCAPE = 5
INSIDE_DOUBLE_QUOTE = 6
INSIDE_DOUBLE_QUOTE_ESCAPE = 7
def __init__(self):
self._output = ''
self._codeblock = ''
def flush_codeblock(self):
stripped = re.sub(r"\s+", ' ', self._codeblock)
stripped = re.sub(r";?\s*(?P<op>[{};])\s*", r'\g<op>', stripped)
self._output += stripped
self._codeblock = ''
def parse(self, content):
state = self.INITIAL
for char in content:
if state == self.INITIAL:
if char == '/':
state = self.MAYBE_COMMENT_START
elif char == "'":
self.flush_codeblock()
self._output += char
state = self.INSIDE_SINGLE_QUOTE
elif char == '"':
self.flush_codeblock()
self._output += char
state = self.INSIDE_DOUBLE_QUOTE
else:
self._codeblock += char
elif state == self.MAYBE_COMMENT_START:
if char == '*':
self.flush_codeblock()
state = self.INSIDE_COMMENT
else:
self._codeblock += '/' + char
state = self.INITIAL
elif state == self.INSIDE_COMMENT:
if char == '*':
state = self.MAYBE_COMMENT_END
else:
pass
elif state == self.MAYBE_COMMENT_END:
if char == '/':
state = self.INITIAL
else:
state = self.INSIDE_COMMENT
elif state == self.INSIDE_SINGLE_QUOTE:
if char == '\\':
self._output += char
state = self.INSIDE_SINGLE_QUOTE_ESCAPE
elif char == "'":
self._output += char
state = self.INITIAL
else:
self._output += char
elif state == self.INSIDE_SINGLE_QUOTE_ESCAPE:
self._output += char
state = self.INSIDE_SINGLE_QUOTE
elif state == self.INSIDE_DOUBLE_QUOTE:
if char == '\\':
self._output += char
state = self.INSIDE_DOUBLE_QUOTE_ESCAPE
elif char == '"':
self._output += char
state = self.INITIAL
else:
self._output += char
elif state == self.INSIDE_DOUBLE_QUOTE_ESCAPE:
self._output += char
state = self.INSIDE_DOUBLE_QUOTE
self.flush_codeblock()
self._output = self._output.strip()
return self._output
@classmethod
def minimize_css(cls, content):
minimizer = CSSMinimizer()
return minimizer.parse(content)
def main():
result = ''
try:
result = CSSMinimizer.minimize_css(sys.stdin.read())
finally:
print(result)
if __name__ == '__main__':
main()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment