GRIT

Google Resource and Internationalization Tool






Lu Yuan
2014-8-1

heX 遇到的问题

打包
HTML CSS JavaScript Image Data...

档案文件: zip, 7z, tar...
  • 解压到硬盘通过本地路径或者自定义协议读取
  • 解压到内存通过自定义协议读取

追加至可执行文件中
不太现实!!!

Chromium 是如何解决的


Chromium 中包含大量的 web 资源。

除了任务管理器以外的窗口几乎全部使用 web 前端渲染。


它们在哪?

resources.pak

Chromium 如何读取资源

1. 准备 GRD 文件 (构建期)

<?xml version="1.0" encoding="UTF-8"?><grit current_release="1" latest_public_release="0">
<outputs>
<output filename="grit/devtools_resources.h" type="rc_header">
<emit emit_type="prepend"/>
</output>
<output filename="grit/devtools_resources_map.cc" type="resource_file_map_source"/>
<output filename="grit/devtools_resources_map.h" type="resource_map_header"/>

<output filename="devtools_resources.pak" type="data_package"/>
</outputs>
<release seq="1">
<includes>
<include file="devtools.html" name="DEVTOOLS_HTML" type="BINDATA"/>
<include file="inspector.js" name="INSPECTOR_JS" type="BINDATA"/>
<include file="ElementsPanel.js" name="ELEMENTSPANEL_JS" type="BINDATA"/>
<include file="ResourcesPanel.js" name="RESOURCESPANEL_JS" type="BINDATA"/>
<include file="NetworkPanel.js" name="NETWORKPANEL_JS" type="BINDATA"/>
<include file="ScriptsPanel.js" name="SCRIPTSPANEL_JS" type="BINDATA"/>
<include file="TimelinePanel.js" name="TIMELINEPANEL_JS" type="BINDATA"/>
<include file="ProfilesPanel.js" name="PROFILESPANEL_JS" type="BINDATA"/>
<include file="AuditsPanel.js" name="AUDITSPANEL_JS" type="BINDATA"/>
<include file="LayersPanel.js" name="LAYERSPANEL_JS" type="BINDATA"/>
<include file="CodeMirrorTextEditor.js" name="CODEMIRRORTEXTEDITOR_JS" type="BINDATA"/> ......
变态!连 GRD 都要脚本生成

Chromium 如何读取资源

2. grit 生成 pak, h... (编译期)

  • grit 命令传入参数生成目标文件
    (包括 resource id)
  • 将多个 pak 文件合并
  • 将合并后的文件复制到目标目录
       'actions': [
{
'action_name': 'devtools_resources',
# This can't use build/grit_action.gypi because the grd file
# is generated at build time, so the trick of using grit_info to get
# the real inputs/outputs at GYP time isn't possible.
'variables': {
'grit_cmd': ['python', '../../../tools/grit/grit.py'],
'grit_grd_file': '<(SHARED_INTERMEDIATE_DIR)/devtools/devtools_resources.grd',
},
'inputs': [
'<(grit_grd_file)',
'<!@pymod_do_main(grit_info --inputs)',
],
'outputs': [
'<(grit_out_dir)/grit/devtools_resources.h',
'<(grit_out_dir)/devtools_resources.pak',
'<(grit_out_dir)/grit/devtools_resources_map.cc',
'<(grit_out_dir)/grit/devtools_resources_map.h',
],
'action': ['<@(grit_cmd)',
'-i', '<(grit_grd_file)', 'build',
'-f', 'GRIT_DIR/../gritsettings/resource_ids',
'-o', '<(grit_out_dir)',
'-D', 'SHARED_INTERMEDIATE_DIR=<(SHARED_INTERMEDIATE_DIR)',
'<@(grit_defines)' ],
'message': 'Generating resources from <(grit_grd_file)',
'msvs_cygwin_shell': 1,
}
],

Chromium 如何读取资源

3. 根据 h 文件从 pak 文件中读取资源内容 (运行期)

  • 解析 URL (chrome://xxx/index.html)
  • 获取 resource id
  • 根据 resource id 读取资源内容 (memory mapping)
  • 判断 MIME type
  • 设置 stream
  • ...




Chromium 如何读取资源

4. 支持模板

         <div id="logo">
<div id="company"><img src="hex_logo.png" /></div>
<div id="copyright">Copyright &copy; $$YEAR$$ NetEase Youdao Inc. and other heX contributors.<br/>All rights reserved.<br/><a href="chrome://license">license</a> | <a href="chrome://credits">credits</a></div>
</div>
<table id="inner" cellpadding="0" cellspacing="0" border="0">
<tr>
<td class="label" valign="top">heX</td>
<td class="value">$$HEX$$</td>
</tr>
<tr>
<td class="label" valign="top">Node.js</td>
<td class="value">$$NODE$$</td>
</tr>
<tr>
<td class="label" valign="top">CEF</td>
<td class="value">$$CEF$$</td>
</tr>
<tr>
<td class="label" valign="top">Chromium</td>
<td class="value">$$CHROMIUM$$</td> ...

     parser.Add("HEX",
base::StringPrintf("%d.%d.%d-%s",
HEX_VERSION_MAJOR,
HEX_VERSION_MINOR,
HEX_VERSION_BUILD,
HEX_REVISION));
if (hex::CanUseNode()) {
parser.Add("NODE", base::StringPrintf("%s", NODE_VERSION_STRING));
} else {
parser.Add("NODE", base::StringPrintf("%s", "Not found"));
}



Resource id 从何而来

src/tools/gritsettings/resource_ids

 {
"SRCDIR": "../..",

"cef/libcef/resources/cef_resources.grd": {
"includes": [27500],
},
"cef/libcef/resources/cef_strings.grd": {
"messages": [28000],
},
"hex/src/resources/hex_resources.grd": {
"includes": [100],
},
"hex/web_resources/web_resources.grd": {
"includes": [50000],
},
"chrome/browser/browser_resources.grd": {
"includes": [500],
"structures": [750],
},
"chrome/browser/resources/component_extension_resources.grd": {
"includes": [1000],
"structures": [1450],
},
"chrome/browser/resources/net_internals_resources.grd": {
"includes": [1500],
},
"ui/webui/resources/webui_resources.grd": {
"includes": [2000],
"structures": [2200],
},
"chrome/common/common_resources.grd": {
"includes": [2500],
},
"chrome/renderer/resources/renderer_resources.grd": {
"includes": [3500],
"structures": [3700],
},
"net/base/net_resources.grd": {
"includes": [4000],
},
"ui/resources/ui_unscaled_resources.grd": {
"includes": [4500],
},
"webkit/glue/resources/webkit_resources.grd": {
"structures": [4700],
},
"webkit/tools/test_shell/test_shell_resources.grd": {
"includes": [5000],
},
"ui/resources/ui_resources.grd": {
"structures": [5500],
},
"ash/resources/ash_resources.grd": {
"includes": [6100],
"structures": [6150],
},
"chrome/app/theme/theme_resources.grd": {
"structures": [6500],
},
"chrome/app/theme/chrome_unscaled_resources.grd": {
"includes": [7500],
},
"chrome_frame/resources/chrome_frame_resources.grd": {
"includes": [8000],
},
"ui/base/strings/app_locale_settings.grd": {
"messages": [9000],
},
"chrome/app/resources/locale_settings.grd": {
"includes": [9500],
"messages": [10000],
},
# These each start with the same resource id because we only use one
# file for each build (chromiumos, google_chromeos, linux, mac, or win).
"chrome/app/resources/locale_settings_chromiumos.grd": {
"messages": [10500],
},
"chrome/app/resources/locale_settings_google_chromeos.grd": {
"messages": [10500],
},
"chrome/app/resources/locale_settings_linux.grd": {
"messages": [10500],
},
"chrome/app/resources/locale_settings_mac.grd": {
"messages": [10500],
},
"chrome/app/resources/locale_settings_win.grd": {
"messages": [10500],
},

"ui/base/strings/ui_strings.grd": {
"messages": [11000],
},
# Chromium strings and Google Chrome strings must start at the same id.
# We only use one file depending on whether we're building Chromium or
# Google Chrome.
"chrome/app/chromium_strings.grd": {
"messages": [11500],
},
"chrome/app/google_chrome_strings.grd": {
"messages": [11500],
},
# Leave lots of space for generated_resources since it has most of our
# strings.
"chrome/app/generated_resources.grd": {
"structures": [12000],
"messages": [12500],
},
# The chrome frame dialogs are also in generated_resources.grd so they
# get included by the translation console. We make sure that the ids
# for structures here are the same as for generated_resources.grd.
"chrome_frame/resources/chrome_frame_dialogs.grd": {
"structures": [12000],
"includes": [12250],
},
"webkit/glue/inspector_strings.grd": {
"messages": [17500],
},
"webkit/glue/webkit_strings.grd": {
"messages": [18000],
},

"chrome_frame/resources/chrome_frame_resources.grd": {
"includes": [19000],
"structures": [19500],
},

"ui/base/native_theme/resources/native_theme_resources.grd": {
"includes": [20000],
},

"chrome/app/policy/policy_templates.grd": {
"structures": [20500],
"messages": [20510],
},

"chrome/browser/autofill/autofill_resources.grd": {
"messages": [21000],
},
"chrome/browser/resources/sync_internals_resources.grd": {
"includes": [21500],
},
"chrome/browser/resources/signin_internals_resources.grd": {
"includes": [21750],
},
# This file is generated during the build.
# devtools_resources.grd can be in two different places depending on whether
# we are in a chromium checkout or a webkit-only checkout.
"<(SHARED_INTERMEDIATE_DIR)/devtools/devtools_resources.grd": {
"includes": [22000],
},
"devtools_resources.grd": {
"includes": [22000],
},
# This file is generated during the build.
"chrome/browser/devtools/frontend/devtools_discovery_page_resources.grd": {
"includes": [22500],
},
"chrome/browser/resources/options_resources.grd": {
"includes": [23000],
},
"chrome/browser/resources/options_resources.grd": {
"structures": [23200],
},
"cloud_print/virtual_driver/win/install/virtual_driver_setup_resources.grd": {
"messages": [23500],
"includes": [23550],
},
"cloud_print/service/win/service_resources.grd": {
"messages": [23600],
"includes": [23800],
"structures": [23900],
},
"chrome/browser/resources/quota_internals_resources.grd": {
"includes": [24000],
},
"content/content_resources.grd": {
"includes": [25000],
},
"content/shell/shell_resources.grd": {
"includes": [25500],
},
# This file is generated during the build.
"<(SHARED_INTERMEDIATE_DIR)/content/browser/tracing/tracing_resources.grd": {
"includes": [25750],
},
"ash/ash_strings.grd": {
"messages": [26000],
},
"chrome/common/extensions_api_resources.grd": {
"includes": [26500],
},
"third_party/trace-viewer/src/tracing.grd": {
"includes": [27000],
},
"chrome/browser/resources/memory_internals_resources.grd": {
"includes": [27500],
},
"device/bluetooth/bluetooth_strings.grd": {
"messages": [28000],
},
"ui/keyboard/keyboard_resources.grd": {
"includes": [28050],
},
"chrome/browser/resources/translate_internals_resources.grd": {
"includes": [28500],
},
"chrome/browser/resources/sync_file_system_internals_resources.grd": {
"includes": [29000],
},
"components/component_strings.grd": {
"messages": [30000],
},
"third_party/WebKit/public/blink_resources.grd": {
"includes": [30500],
},
# Resource ids starting at 31000 are reserved for projects built on Chromium.
}




Messages 是什么?

i18n

  • src/chrome/app/chromium_strings.grd
  • src/chrome/app/google_chrome_strings.grd
  • src/chrome/app/generated_resources.grd
    • resources/generated_resources_zh-CN.xtb
    • ...


52 XTBs

GRD ---------------- PAK

heX 的解决方案

  1. 对 grit 稍作修改增加输出 JSON 资源文件功能
    { "index.html": 50000, "js/main.js": 50001 }
  2. 用 grit 同时生成 JSON 及 PAK 文件
  3. 启动后注册 chrome 协议的时候解析 JSON
  4. Request URL 是根据 path 找到 resource id
  5. 通过 resource id 找到资源内容
  6. ...



乌玵完




谢谢大家!

GRIT

By luyuan

GRIT

  • 3,016