CINXE.COM
Chromium Blog: 2008
<!DOCTYPE html> <html class='v2 list-page' dir='ltr' itemscope='' itemtype='http://schema.org/Blog' lang='en' xmlns='http://www.w3.org/1999/xhtml' xmlns:b='http://www.google.com/2005/gml/b' xmlns:data='http://www.google.com/2005/gml/data' xmlns:expr='http://www.google.com/2005/gml/expr'> <head> <link href='https://www.blogger.com/static/v1/widgets/3566091532-css_bundle_v2.css' rel='stylesheet' type='text/css'/> <title> Chromium Blog: 2008 </title> <meta content='width=device-width, height=device-height, initial-scale=1.0' name='viewport'/> <meta content='IE=Edge' http-equiv='X-UA-Compatible'/> <meta content='Chromium Blog' property='og:title'/> <meta content='en_US' property='og:locale'/> <meta content='https://blog.chromium.org/2008/' property='og:url'/> <meta content='Chromium Blog' property='og:site_name'/> <!-- Twitter Card properties --> <meta content='Chromium Blog' property='og:title'/> <meta content='summary' name='twitter:card'/> <meta content='@ChromiumDev' name='twitter:creator'/> <link href='https://fonts.googleapis.com/css?family=Roboto:400italic,400,500,500italic,700,700italic' rel='stylesheet' type='text/css'/> <link href='https://fonts.googleapis.com/icon?family=Material+Icons' rel='stylesheet'/> <script src='https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js' type='text/javascript'></script> <!-- End --> <style id='page-skin-1' type='text/css'><!-- /* <Group description="Header Color" selector="header"> <Variable name="header.background.color" description="Header Background" type="color" default="#ffffff"/> </Group> */ .header-outer { border-bottom: 1px solid #e0e0e0; background: #ffffff; } html, .Label h2, #sidebar .rss a, .BlogArchive h2, .FollowByEmail h2.title, .widget .post h2 { font-family: Roboto, sans-serif; } .plusfollowers h2.title, .post h2.title, .widget h2.title { font-family: Roboto, sans-serif; } .widget-item-control { height: 100%; } .widget.Header, #header { position: relative; height: 100%; width: 100%; } } .widget.Header .header-logo1 { float: left; margin-right: 15px; padding-right: 15px; border-right: 1px solid #ddd; } .header-title h2 { color: rgba(0,0,0,.54); display: inline-block; font-size: 40px; font-family: Roboto, sans-serif; font-weight: normal; line-height: 76px; vertical-align: top; } .header-inner { background-repeat: no-repeat; background-position: right 0px; } .post-author, .byline-author { font-size: 14px; font-weight: normal; color: #757575; color: rgba(0,0,0,.54); } .post-content .img-border { border: 1px solid rgb(235, 235, 235); padding: 4px; } .header-title a { text-decoration: none !important; } pre { border: 1px solid #bbbbbb; margin-top: 1em 0 0 0; padding: 0.99em; overflow-x: auto; overflow-y: auto; } pre, code { font-size: 9pt; background-color: #fafafa; line-height: 125%; font-family: monospace; } pre, code { color: #060; font: 13px/1.54 "courier new",courier,monospace; } .header-left .header-logo1 { width: 128px !important; } .header-desc { line-height: 20px; margin-top: 8px; } .fb-custom img, .twitter-custom img, .gplus-share img { cursor: pointer; opacity: 0.54; } .fb-custom img:hover, .twitter-custom img:hover, .gplus-share img:hover { opacity: 0.87; } .fb-like { width: 80px; } .post .share { float: right; } #twitter-share{ border: #CCC solid 1px; border-radius: 3px; background-image: -webkit-linear-gradient(top,#ffffff,#dedede); } .twitter-follow { background: url(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimKBWDeRb1pqsbNiP9AFLyFDZHzXGYEJZRELMrZ6iI0yz4KeMPH_7tPsrMq9PpJ3H6riC_UohpWMn83_Z1N2sTuTTrVL7i6TrNzpO9oFg4e8VFK4zFJb1rfamWfc8RxG8Fhz2RgRgHN10u/s1600/twitter-bird.png) no-repeat left center; padding-left: 18px; font: normal normal normal 11px/18px 'Helvetica Neue',Arial,sans-serif; font-weight: bold; text-shadow: 0 1px 0 rgba(255,255,255,.5); cursor: pointer; margin-bottom: 10px; } .twitter-fb { padding-top: 2px; } .fb-follow-button { background: -webkit-linear-gradient(#4c69ba, #3b55a0); background: -moz-linear-gradient(#4c69ba, #3b55a0); background: linear-gradient(#4c69ba, #3b55a0); border-radius: 2px; height: 18px; padding: 4px 0 0 3px; width: 57px; border: #4c69ba solid 1px; } .fb-follow-button a { text-decoration: none !important; text-shadow: 0 -1px 0 #354c8c; text-align: center; white-space: nowrap; font-size: 11px; color: white; vertical-align: top; } .fb-follow-button a:visited { color: white; } .fb-follow { padding: 0px 5px 3px 0px; width: 14px; vertical-align: bottom; } .gplus-wrapper { margin-top: 3px; display: inline-block; vertical-align: top; } .twitter-custom, .gplus-share { margin-right: 12px; } .fb-follow-button{ margin: 10px auto; } /** CUSTOM CODE **/ --></style> <style id='template-skin-1' type='text/css'><!-- .header-outer { clear: both; } .header-inner { margin: auto; padding: 0px; } .footer-outer { background: #f5f5f5; clear: both; margin: 0; } .footer-inner { margin: auto; padding: 0px; } .footer-inner-2 { /* Account for right hand column elasticity. */ max-width: calc(100% - 248px); } .google-footer-outer { clear: both; } .cols-wrapper, .google-footer-outer, .footer-inner, .header-inner { max-width: 978px; margin-left: auto; margin-right: auto; } .cols-wrapper { margin: auto; clear: both; margin-top: 60px; margin-bottom: 60px; overflow: hidden; } .col-main-wrapper { float: left; width: 100%; } .col-main { margin-right: 278px; max-width: 660px; } .col-right { float: right; width: 248px; margin-left: -278px; } /* Tweaks for layout mode. */ body#layout .google-footer-outer { display: none; } body#layout .header-outer, body#layout .footer-outer { background: none; } body#layout .header-inner { height: initial; } body#layout .cols-wrapper { margin-top: initial; margin-bottom: initial; } --></style> <!-- start all head --> <meta content='text/html; charset=UTF-8' http-equiv='Content-Type'/> <meta content='blogger' name='generator'/> <link href='https://blog.chromium.org/favicon.ico' rel='icon' type='image/x-icon'/> <link href='https://blog.chromium.org/2008/' rel='canonical'/> <link rel="alternate" type="application/atom+xml" title="Chromium Blog - Atom" href="https://blog.chromium.org/feeds/posts/default" /> <link rel="alternate" type="application/rss+xml" title="Chromium Blog - RSS" href="https://blog.chromium.org/feeds/posts/default?alt=rss" /> <link rel="service.post" type="application/atom+xml" title="Chromium Blog - Atom" href="https://www.blogger.com/feeds/2471378914199150966/posts/default" /> <!--Can't find substitution for tag [blog.ieCssRetrofitLinks]--> <meta content='https://blog.chromium.org/2008/' property='og:url'/> <meta content='Chromium Blog' property='og:title'/> <meta content='News and developments from the open source browser project' property='og:description'/> <!-- end all head --> <base target='_self'/> <style> html { font-family: Roboto, sans-serif; -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; } body { padding: 0; /* This ensures that the scroll bar is always present, which is needed */ /* because content render happens after page load; otherwise the header */ /* would "bounce" in-between states. */ min-height: 150%; } h2 { font-size: 16px; } h1, h2, h3, h4, h5 { line-height: 2em; } html, h4, h5, h6 { font-size: 14px; } a, a:visited { /* Ensures links meet minimum contrast ratios. */ color: #3974d6; text-decoration: none; } a:focus, a:hover, a:active { text-decoration: none; } .Header { margin-top: 15px; } .Header h1 { font-size: 32px; font-weight: 300; line-height: 32px; height: 42px; } .header-inner .Header .titlewrapper { padding: 0; margin-top: 30px; } .header-inner .Header .descriptionwrapper { padding: 0; margin: 0; } .cols-wrapper { margin-top: 56px; } .header-outer, .cols-wrapper, .footer-outer, .google-footer-outer { padding: 0 60px; } .header-inner { height: 256px; position: relative; } html, .header-inner a { color: #212121; color: rgba(0,0,0,.87); } .header-inner .google-logo { display: inline-block; background-size: contain; z-index: 1; height: 70px; overflow: hidden; margin-top: 4px; margin-right: 8px; } .header-left { position: absolute; top: 50%; -webkit-transform: translateY(-50%); transform: translateY(-50%); margin-top: 12px; width: 100%; } .google-logo { margin-left: -4px; } .google-logo img{ height:70px; } #google-footer { position: relative; font-size: 13px; list-style: none; text-align: right; } #google-footer a { color: #444; } #google-footer ul { margin: 0; padding: 0; height: 144px; line-height: 144px; } #google-footer ul li { display: inline; } #google-footer ul li:before { color: #999; content: "\00b7"; font-weight: bold; margin: 5px; } #google-footer ul li:first-child:before { content: ''; } #google-footer .google-logo-dark { left: 0; margin-top: -16px; position: absolute; top: 50%; } /** Sitemap links. **/ .footer-inner-2 { font-size: 14px; padding-top: 42px; padding-bottom: 74px; } .footer-inner-2 .HTML h2 { color: #212121; color: rgba(0,0,0,.87); font-size: 14px; font-weight: 500; padding-left: 0; margin: 10px 0; } .footer-inner-2 .HTML ul { font-weight: normal; list-style: none; padding-left: 0; } .footer-inner-2 .HTML li { line-height: 24px; padding: 0; } .footer-inner-2 li a { color: rgba(65,132,243,.87); } /** Archive widget. **/ .BlogArchive { font-size: 13px; font-weight: normal; } .BlogArchive .widget-content { display: none; } .BlogArchive h2, .Label h2 { color: #4184F3; text-decoration: none; } .BlogArchive .hierarchy li { display: inline-block; } /* Specificity needed here to override widget CSS defaults. */ .BlogArchive #ArchiveList ul li, .BlogArchive #ArchiveList ul ul li { margin: 0; padding-left: 0; text-indent: 0; } .BlogArchive .intervalToggle { cursor: pointer; } .BlogArchive .expanded .intervalToggle .new-toggle { -ms-transform: rotate(180deg); transform: rotate(180deg); } .BlogArchive .new-toggle { float: right; padding-top: 3px; opacity: 0.87; } #ArchiveList { text-transform: uppercase; } #ArchiveList .expanded > ul:last-child { margin-bottom: 16px; } #ArchiveList .archivedate { width: 100%; } /* Months */ .BlogArchive .items { max-width: 150px; margin-left: -4px; } .BlogArchive .expanded .items { margin-bottom: 10px; overflow: hidden; } .BlogArchive .items > ul { float: left; height: 32px; } .BlogArchive .items a { padding: 0 4px; } .Label { font-size: 13px; font-weight: normal; } .sidebar-icon { display: inline-block; width: 24px; height: 24px; vertical-align: middle; margin-right: 12px; margin-top: -1px } .Label a { margin-right: 4px; } .Label .widget-content { display: none; } .FollowByEmail { font-size: 13px; font-weight: normal; } .FollowByEmail h2 { background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAALCAYAAACZIGYHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAUBJREFUeNrMkSGLAlEUhb+ZB4JFi8mx2cz+ApvhRUGTcUCrNqNJDYIi+DO0GUwmQXDK2DSIoGgZcSaIjDrzwrK4ssvChj1w0733O+fdp+m6PozH4yQSCfb7Pa7r8pOi0SjJZBLP8zgej4gAIMvlMuPxmADIYrHger1+C6lUKmo+NJ/NZojb7SZDWiwWo1qtks1msW2bw+HwZdkwDHq9HvV6nel0SqvVYrvdIh6Ph3Qch+VyqRYLhQJSSjRNw7IsfN9XgGKxSLfbJZfL0e/3aTabrFYr7vc7IujLcOh8PqunrNdr0uk0pVKJVCpFJBJRgEajweVyod1uMxgM2O12BAGUgRbU8DV2JpOhVquRz+cRQii3+XxOp9NRN3jVR5LPOp1OjEYjlSL8hclkgmmabDabt4d+m+S30vkD/R/IU4ABAPTZgnZdmG/PAAAAAElFTkSuQmCC"); background-repeat: no-repeat; background-position: 0 50%; text-indent: 30px; } .FollowByEmail .widget-content { display: none; } .searchBox input { border: 1px solid #eee; color: #212121; color: rgba(0,0,0,.87); font-size: 14px; padding: 8px 8px 8px 40px; width: 164px; font-family: Roboto, sans-serif; background: url("https://www.gstatic.com/images/icons/material/system/1x/search_grey600_24dp.png") 8px center no-repeat; } .searchBox ::-webkit-input-placeholder { /* WebKit, Blink, Edge */ color: rgba(0,0,0,.54); } .searchBox :-moz-placeholder { /* Mozilla Firefox 4 to 18 */ color: #000; opacity: 0.54; } .searchBox ::-moz-placeholder { /* Mozilla Firefox 19+ */ color: #000; opacity: 0.54; } .searchBox :-ms-input-placeholder { /* Internet Explorer 10-11 */ color: #757575; } .widget-item-control { margin-top: 0px; } .section { margin: 0; padding: 0; } #sidebar-top { border: 1px solid #eee; } #sidebar-top > div { margin: 16px 0; } .widget ul { line-height: 1.6; } /*main post*/ .post { margin-bottom:30px; } #main .post .title { margin: 0; } #main .post .title a { color: #212121; color: rgba(0,0,0,.87); font-weight: normal; font-size: 24px; } #main .post .title a:hover { text-decoration:none; color: #3974d6; } .message, #main .post .post-header { margin: 0; padding: 0; } #main .post .post-header .caption, #main .post .post-header .labels-caption, #main .post .post-footer .caption, #main .post .post-footer .labels-caption { color: #444; font-weight: 500; } #main .tr-caption-container td { text-align: left; } #main .post .tr-caption { color: #757575; color: rgba(0,0,0,.54); display: block; max-width: 560px; padding-bottom: 20px; } #main .post .tr-caption-container { line-height: 24px; margin: -1px 0 0 0 !important; padding: 4px 0; text-align: left; } #main .post .post-header .published{ font-size:11px; font-weight:bold; } .post-header .publishdate { font-size: 17px; font-weight:normal; color: #757575; color: rgba(0,0,0,.54); } #main .post .post-footer{ font-size:12px; padding-bottom: 21px; } .label-footer { margin-bottom: 12px; margin-top: 12px; } .comment-img { margin-right: 16px; opacity: 0.54; vertical-align: middle; } #main .post .post-header .published { margin-bottom: 40px; margin-top: -2px; } .post .post-content { color: #212121; color: rgba(0,0,0,.87); font-size: 17px; margin: 25px 0 36px 0; line-height: 32px; } .post-body .post-content ul, .post-body .post-content ol { margin: 16px 0; padding: 0 48px; } .post-summary { display: none; } /* Another old-style caption. */ .post-content div i, .post-content div + i { font-size: 14px; font-style: normal; color: #757575; color: rgba(0,0,0,.54); display: block; line-height: 24px; margin-bottom: 16px; text-align: left; } /* Another old-style caption (with link) */ .post-content a > i { color: #4184F3 !important; } /* Old-style captions for images. */ .post-content .separator + div:not(.separator) { margin-top: -16px; } /* Capture section headers. */ .post-content br + br + b, .post-content .space + .space + b, .post-content .separator + b { display: inline-block; margin-bottom: 8px; margin-top: 24px; } .post-content li { line-height: 32px; } /* Override all post images/videos to left align. */ .post-content .separator, .post-content > div { text-align: left; } .post-content .separator > a, .post-content .separator > span { margin-left: 0 !important; } .post-content img { max-width: 100%; height: auto; width: auto; } .post-content .tr-caption-container img { margin-bottom: 12px; } .post-content iframe, .post-content embed { max-width: 100%; } .post-content .carousel-container { margin-bottom: 48px; } #main .post-content b { font-weight: 500; } /* These are the main paragraph spacing tweaks. */ #main .post-content br { content: ' '; display: block; padding: 4px; } .post-content .space { display: block; height: 8px; } .post-content iframe + .space, .post-content iframe + br { padding: 0 !important; } #main .post .jump-link { margin-bottom:10px; } .post-content img, .post-content iframe { margin: 30px 0 20px 0; } .post-content > img:first-child, .post-content > iframe:first-child { margin-top: 0; } .col-right .section { padding: 0 16px; } #aside { background:#fff; border:1px solid #eee; border-top: 0; } #aside .widget { margin:0; } #aside .widget h2, #ArchiveList .toggle + a.post-count-link { color: #212121; color: rgba(0,0,0,.87); font-weight: 400 !important; margin: 0; } #ArchiveList .toggle { float: right; } #ArchiveList .toggle .material-icons { padding-top: 4px; } #sidebar .tab { cursor: pointer; } #sidebar .tab .arrow { display: inline-block; float: right; } #sidebar .tab .icon { display: inline-block; vertical-align: top; height: 24px; width: 24px; margin-right: 13px; margin-left: -1px; margin-top: 1px; color: #757575; color: rgba(0,0,0,.54); } #sidebar .widget-content > :first-child { padding-top: 8px; } #sidebar .active .tab .arrow { -ms-transform: rotate(180deg); transform: rotate(180deg); } #sidebar .arrow { color: #757575; color: rgba(0,0,0,.54); } #sidebar .widget h2 { font-size: 14px; line-height: 24px; display: inline-block; } #sidebar .widget .BlogArchive { padding-bottom: 8px; } #sidebar .widget { border-bottom: 1px solid #eee; box-shadow: 0px 1px 0 white; margin-bottom: 0; padding: 14px 0; min-height: 20px; } #sidebar .widget:last-child { border-bottom: none; box-shadow: none; margin-bottom: 0; } #sidebar ul { margin: 0; padding: 0; } #sidebar ul li { list-style:none; padding:0; } #sidebar ul li a { line-height: 32px; } #sidebar .archive { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAYCAYAAADzoH0MAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAE1JREFUeNpiNDY23s9AAWBioBCwYBM8c+YMVsUmJibEGYBNMS5DaeMFfDYSZQA2v9I3FrB5AZeriI4FmnrBccCT8mhmGs1MwyAzAQQYAKEWG9zm9QFEAAAAAElFTkSuQmCC"); height: 24px; line-height: 24px; padding-left: 30px; } #sidebar .labels { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAYAAAA7bUf6AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAUxJREFUeNpiNDY23s9AAMycOfM7UF05kHkZmzwTMkdSUhKrIcXFxZy3bt3qBjIN8RrS09PDsHnzZjCNDr58+cKQlpbGDjSoHcg1w2oIyAUODg5gARCNzUVIBrUCuVYYhjx//pzhwIEDYAEQDeJjA1CDWIAGNQK59jBxRuSABbkAlwHIgIeHh2HWrFn/1NTU2oDcvSgBS4wBSC5iArqoCsj1YGIgEyAZVMoEchqlBjEB/cZAiUHg2AEGznpKDAImxOeM////B4VLKtBvEUCngZ1ILKivr3/u6+ubBzJAGZQ9gC5aQoqLgAY8BhkAZL4BuQQkxgXE34A4BuiiZEIuAhrwEGhAEZD5DpzYoIaA2UAM4kQADUrHZRDUgAIg8wO2XAwzbQXQa5OweQ1owB10AyA6gS7BgX1u3ry5397eHow3bdo0EyjGi00tQIABANPgyAH1q1eaAAAAAElFTkSuQmCC"); height: 20px; line-height: 20px; padding-left: 30px; } #sidebar .rss a { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAX5JREFUeNqsVDGSgkAQHL2rIiIikohIc/EBRkbwAIwuwgfwAXiAD9AHSI7kEkECRCb6AIyINDLx7K0aa6kT7uq0q7YYtnZ7umdnt7darXbr9Zpegeu61DNNc0dvwCcH4/GYJpMJnc9nOhwOVJbl/4hAAokMECZJQtvt9k+kH7qufyEYDAakqqqYxFdRFBqNRmTbNg2HQ0rTlK7XayvR0xqBdDqdkuM4dE/0ULhYLOh4PHYrknG5XGi/31MYhuL/nkwonM1mlGUZ1XXdrsiyLGEDhY7juJEZ1u5tIixDGdYhmYw+B7CAzPP5nDabjdgIAgCksMX1832/3drtdqPT6SQWapomiGEFNkDEdpDMMAzK81ys/7XYy+XyoQgq2WoURSIJ2iIIgp/WZCCTvFm2wgeAU31aI3Q2GhIDMeB53qPYPIcm5VrxXIOIOxsDMStjVawAc1VViRgN22lNBiuQN3GR+SY07hpOoStmFQAKXRRFY93bnpG+fONfedi+BRgAbkS8Fxp7QQIAAAAASUVORK5CYII="); } #sidebar .subscription a { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAALCAYAAACZIGYHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAUBJREFUeNrMkSGLAlEUhb+ZB4JFi8mx2cz+ApvhRUGTcUCrNqNJDYIi+DO0GUwmQXDK2DSIoGgZcSaIjDrzwrK4ssvChj1w0733O+fdp+m6PozH4yQSCfb7Pa7r8pOi0SjJZBLP8zgej4gAIMvlMuPxmADIYrHger1+C6lUKmo+NJ/NZojb7SZDWiwWo1qtks1msW2bw+HwZdkwDHq9HvV6nel0SqvVYrvdIh6Ph3Qch+VyqRYLhQJSSjRNw7IsfN9XgGKxSLfbJZfL0e/3aTabrFYr7vc7IujLcOh8PqunrNdr0uk0pVKJVCpFJBJRgEajweVyod1uMxgM2O12BAGUgRbU8DV2JpOhVquRz+cRQii3+XxOp9NRN3jVR5LPOp1OjEYjlSL8hclkgmmabDabt4d+m+S30vkD/R/IU4ABAPTZgnZdmG/PAAAAAElFTkSuQmCC"); } #sidebar-bottom { background: #f5f5f5; border-top:1px solid #eee; } #sidebar-bottom .widget { border-bottom: 1px solid #e0e0e0; padding: 15px 0; text-align: center; } #sidebar-bottom > div:last-child { border-bottom: 0; } #sidebar-bottom .text { line-height: 20px; } /* Home, forward, and backward pagination. */ .blog-pager { border-top : 1px #e0e0e0 solid; padding-top: 10px; margin-top: 15px; text-align: right !important; } #blog-pager { margin-botom: 0; margin-top: -14px; padding: 16px 0 0 0; } #blog-pager a { display: inline-block; } .blog-pager i.disabled { opacity: 0.2 !important; } .blog-pager i { color: black; margin-left: 16px; opacity: 0.54; } .blog-pager i:hover, .blog-pager i:active { opacity: 0.87; } #blog-pager-older-link, #blog-pager-newer-link { float: none; } .gplus-profile { background-color: #fafafa; border: 1px solid #eee; overflow: hidden; width: 212px; } .gplus-profile-inner { margin-left: -1px; margin-top: -1px; } /* Sidebar follow buttons. */ .followgooglewrapper { padding: 12px 0 0 0; } .loading { visibility: hidden; } .detail-page .post-footer .cmt_iframe_holder { padding-top: 40px !important; } /** Desktop **/ @media (max-width: 900px) { .col-right { display: none; } .col-main { margin-right: 0; min-width: initial; } .footer-outer { display: none; } .cols-wrapper { min-width: initial; } .google-footer-outer { background-color: #f5f5f5; } } /** Tablet **/ @media (max-width: 712px) { .header-outer, .cols-wrapper, .footer-outer, .google-footer-outer { padding: 0 40px; } } /* An extra breakpoint accommodating for long blog titles. */ @media (max-width: 600px) { .header-left { height: 100%; position: initial; top: inherit; margin-top: 0; -webkit-transform: initial; transform: initial; } .header-title { margin-top: 18px; } .header-inner { height: auto; margin-bottom: 32px; margin-top: 32px; } .header-desc { margin-top: 12px; } .header-inner .google-logo { height: 70px; margin-top: 3px; } .header-inner .google-logo img { height: 70px; } .header-title h2 { font-size: 32px; line-height: 76px; } } /** Mobile/small desktop window; also landscape. **/ @media (max-width: 480px), (max-height: 480px) { .header-outer, .cols-wrapper, .footer-outer, .google-footer-outer { padding: 0 16px; } .cols-wrapper { margin-top: 0; } .post-header .publishdate, .post .post-content { font-size: 16px; } .post .post-content { line-height: 28px; margin-bottom: 30px; } .post { margin-top: 30px; } .byline-author { display: block; font-size: 12px; line-height: 24px; margin-top: 6px; } #main .post .title a { font-weight: 500; color: #4c4c4c; color: rgba(0,0,0,.70); } #main .post .post-header { padding-bottom: 12px; } #main .post .post-header .published { margin-bottom: -8px; margin-top: 3px; } .post .read-more { display: block; margin-top: 14px; } .post .tr-caption { font-size: 12px; } #main .post .title a { font-size: 20px; line-height: 30px; } .post-content iframe { /* iframe won't keep aspect ratio when scaled down. */ max-height: 240px; } .post-content .separator img, .post-content .tr-caption-container img, .post-content iframe { margin-left: -16px; max-width: inherit; width: calc(100% + 32px); } .post-content table, .post-content td { width: 100%; } #blog-pager { margin: 0; padding: 16px 0; } /** List page tweaks. **/ .list-page .post-original { display: none; } .list-page .post-summary { display: block; } .list-page .comment-container { display: none; } .list-page #blog-pager { padding-top: 0; border: 0; margin-top: -8px; } .list-page .label-footer { display: none; } .list-page #main .post .post-footer { border-bottom: 1px solid #eee; margin: -16px 0 0 0; padding: 0 0 20px 0; } .list-page .post .share { display: none; } /** Detail page tweaks. **/ .detail-page .post-footer .cmt_iframe_holder { padding-top: 32px !important; } .detail-page .label-footer { margin-bottom: 0; } .detail-page #main .post .post-footer { padding-bottom: 0; } .detail-page #comments { display: none; } } [data-about-pullquote], [data-is-preview], [data-about-syndication] { display: none; } </style> <noscript> <style> .loading { visibility: visible }</style> </noscript> <script type='text/javascript'> (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-37592578-1', 'auto', 'blogger'); ga('blogger.send', 'pageview'); </script> <link href='https://www.blogger.com/dyn-css/authorization.css?targetBlogID=2471378914199150966&zx=3a5e6827-7ceb-4daf-b12c-bebbc55c1d22' media='none' onload='if(media!='all')media='all'' rel='stylesheet'/><noscript><link href='https://www.blogger.com/dyn-css/authorization.css?targetBlogID=2471378914199150966&zx=3a5e6827-7ceb-4daf-b12c-bebbc55c1d22' rel='stylesheet'/></noscript> <meta name='google-adsense-platform-account' content='ca-host-pub-1556223355139109'/> <meta name='google-adsense-platform-domain' content='blogspot.com'/> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?display=swap&family=Roboto"></head> <body> <script type='text/javascript'> //<![CDATA[ var axel = Math.random() + ""; var a = axel * 10000000000000; document.write('<iframe src="https://2542116.fls.doubleclick.net/activityi;src=2542116;type=gblog;cat=googl0;ord=ord=' + a + '?" width="1" height="1" frameborder="0" style="display:none"></iframe>'); //]]> </script> <noscript> <img alt='' height='1' src='https://ad.doubleclick.net/ddm/activity/src=2542116;type=gblog;cat=googl0;ord=1?' width='1'/> </noscript> <!-- Header --> <div class='header-outer'> <div class='header-inner'> <div class='section' id='header'><div class='widget Header' data-version='1' id='Header1'> <div class='header-left'> <div class='header-title'> <a class='google-logo' href='https://blog.chromium.org/'> <img alt="Chromium Blog" height="50" src="//1.bp.blogspot.com/-vkF7AFJOwBk/VkQxeAGi1mI/AAAAAAAARYo/57denvsQ8zA/s1600-r/logo_chromium.png"> </a> <a href='/.'> <h2> Chromium Blog </h2> </a> </div> <div class='header-desc'> News and developments from the open source browser project </div> </div> </div></div> </div> </div> <!-- all content wrapper start --> <div class='cols-wrapper loading'> <div class='col-main-wrapper'> <div class='col-main'> <div class='section' id='main'><div class='widget Blog' data-version='1' id='Blog1'> <div class='post' data-id='3359358371319503370' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2008/12/security-in-depth-password-manager.html' itemprop='url' title='Security in Depth: The Password Manager'> Security in Depth: The Password Manager </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Wednesday, December 17, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <div>Recently a number of articles have discussed the security of browsers' password managers. There are many ways to build a secure password manager, and each browser uses a slightly different approach. In this edition of Security in Depth, we'll look at some of the key security decisions that went into designing the password manager for Google Chrome. As always, we welcome your feedback and suggestions.</div><div><br /></div><div>Password managers improve security in two ways. First, they let users use more complex, harder-to-guess passwords because the password manager does the work of remembering them. Second, they help protect users from <a href="http://en.wikipedia.org/wiki/Phishing">phishing</a> pages (spoof pages that pretend to be from another site) by carefully scrutinizing the web page's URL before revealing the password. The key to the security of a password manager is the algorithm for deciding when to reveal passwords to the current web page. An algorithm that isn't strict enough can reveal users' passwords to compromised or malicious pages. On the other hand, an algorithm that's too strict won't function on some legitimate web sites. This may cause users to use more memorable (and less secure) passwords. Worse, users typically assume the browser is "broken," and become more willing to supply passwords to any page (including harmful ones), since they no longer trust the browser to make correct distinctions. The same side effects are possible if the password manager produces spurious warnings on legitimate sites; this simply trains users to ignore the warnings.</div><div><br /></div><div>The password manager's algorithm is based on the browser's <a href="http://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy">same-origin policy</a>, which <a href="http://blog.chromium.org/2008/12/security-in-depth-local-web-pages.html">we've touched on before</a>. The password manager supplies a password to a page only if the page is from the same origin (same scheme, host, and port) as the original page that saved the password. For example, this algorithm protects passwords from active network attackers by not revealing passwords saved on HTTPS pages to HTTP pages.</div><div><br /></div><div>Because the same-origin policy does not distinguish between different paths, it's tempting to think that we could further improve security by requiring the paths to match as well; for example, passwords saved at <span class="Apple-style-span" style="font-family:'courier new';">https://example.com/login</span> would not be sent to <span class="Apple-style-span" style="font-family:'courier new';">https://example.com/blog</span>. However, this design works poorly with sites where users can log in from several places (like Facebook), as well as sites which store dynamically-generated state in the path. Furthermore, creating this <a href="http://w2spconf.com/2008/papers/s2p1.pdf">"finer-grained" origin</a> wouldn't actually improve security against compromised sites because other parts of the browser (like the JavaScript engine) still obey the same-origin policy. Imagine that <span class="Apple-style-span" style="font-family:'courier new';">example.com</span> has a <a href="http://en.wikipedia.org/wiki/Cross-site_scripting">cross-site scripting</a> vulnerability that lets an attacker inject malicious content into <span class="Apple-style-span" style="font-family:'courier new';">https://example.com/blog</span>. An attacker would not need users to log in to this page; instead, the attacker could simply inject an <iframe> pointing to <span class="Apple-style-span" style="font-family:'courier new';">https://example.com/login</span> and use JavaScript to read the password from that frame.</div><div><br /></div><div>Besides checking the page hosting the password field, we can also check where password data is going to be sent when users submit their information. Consider a scenario that occurred a few years ago on a popular social networking site that let users (or in this case, attackers) customize their profile pages. At the time, an attacker could not include JavaScript on his profile page, but could still use malicious HTML — a password field set to send data back to the attacker's web server. When users viewed the attacker's profile, their password managers would automatically fill in their passwords because the profile page was part of the same origin as the site's login page. Lacking JavaScript, the attacker could not read these passwords immediately, but once the users clicked on the page, their data was sent to the attacker's server. Google Chrome defends against this subtle attack by checking the page to which the password data is submitted, once again using the same-origin policy. If this check fails, the password manager will not automatically fill in passwords when the page is loaded. The downside is that this can trip up legitimate web sites that dynamically generate their login URLs. To help users in both cases, the password manager waits for users to type their user names manually before filling in any passwords. At this point, if a page is really malicious, these users have most likely already fallen for the scam and would have proceeded to type in their passwords manually; continuing to refuse to fill in passwords would merely give the impression that the browser is "broken."</div><div><br /></div><div>A number of other proposals to improve password manager security seem reasonable but don't actually make users more secure. For example, the password manager could refuse to supply passwords to invisible login fields, on the theory that legitimate sites have no need to do this and invisible fields are used only by attackers. Unfortunately, attackers trying to hide password fields from users can make the fields visible but only one pixel tall, or 99% transparent, hidden behind another part of the page, or simply scrolled to a position where users don't normally look. It is impossible for browsers to detect all the various ways password fields can be made difficult to notice, so blocking just one doesn't protect users. Plus, a legitimate site might hide the password field initially (similar to Washington Mutual), and if it does, the password manager wouldn't be able to fill in passwords for this site. </div><div><br /></div><div>We've put a lot of thought into the password manager's design and carefully considered how to defend against a number of threats including phishing, cross-site scripting, and HTTPS certificate errors. By using the password manager, you can choose stronger, more complex passwords that are more difficult to remember. When the password manager refuses to automatically fill in your password, you should pause and consider whether you're viewing a spoof web site. We're also keen to improve the compatibility of the password manager. If you're having trouble using the password manager with your favorite site, consider <a href="http://dev.chromium.org/for-testers/bug-reporting-guidelines">filing a bug</a>.</div><div><br /></div><span class="post-author">Posted by Adam Barth and Tim Steele, Software Engineers</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <div>Recently a number of articles have discussed the security of browsers' password managers. There are many ways to build a secure password manager, and each browser uses a slightly different approach. In this edition of Security in Depth, we'll look at some of the key security decisions that went into designing the password manager for Google Chrome. As always, we welcome your feedback and suggestions.</div><div><br /></div><div>Password managers improve security in two ways. First, they let users use more complex, harder-to-guess passwords because the password manager does the work of remembering them. Second, they help protect users from <a href="http://en.wikipedia.org/wiki/Phishing">phishing</a> pages (spoof pages that pretend to be from another site) by carefully scrutinizing the web page's URL before revealing the password. The key to the security of a password manager is the algorithm for deciding when to reveal passwords to the current web page. An algorithm that isn't strict enough can reveal users' passwords to compromised or malicious pages. On the other hand, an algorithm that's too strict won't function on some legitimate web sites. This may cause users to use more memorable (and less secure) passwords. Worse, users typically assume the browser is "broken," and become more willing to supply passwords to any page (including harmful ones), since they no longer trust the browser to make correct distinctions. The same side effects are possible if the password manager produces spurious warnings on legitimate sites; this simply trains users to ignore the warnings.</div><div><br /></div><div>The password manager's algorithm is based on the browser's <a href="http://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy">same-origin policy</a>, which <a href="http://blog.chromium.org/2008/12/security-in-depth-local-web-pages.html">we've touched on before</a>. The password manager supplies a password to a page only if the page is from the same origin (same scheme, host, and port) as the original page that saved the password. For example, this algorithm protects passwords from active network attackers by not revealing passwords saved on HTTPS pages to HTTP pages.</div><div><br /></div><div>Because the same-origin policy does not distinguish between different paths, it's tempting to think that we could further improve security by requiring the paths to match as well; for example, passwords saved at <span class="Apple-style-span" style="font-family:'courier new';">https://example.com/login</span> would not be sent to <span class="Apple-style-span" style="font-family:'courier new';">https://example.com/blog</span>. However, this design works poorly with sites where users can log in from several places (like Facebook), as well as sites which store dynamically-generated state in the path. Furthermore, creating this <a href="http://w2spconf.com/2008/papers/s2p1.pdf">"finer-grained" origin</a> wouldn't actually improve security against compromised sites because other parts of the browser (like the JavaScript engine) still obey the same-origin policy. Imagine that <span class="Apple-style-span" style="font-family:'courier new';">example.com</span> has a <a href="http://en.wikipedia.org/wiki/Cross-site_scripting">cross-site scripting</a> vulnerability that lets an attacker inject malicious content into <span class="Apple-style-span" style="font-family:'courier new';">https://example.com/blog</span>. An attacker would not need users to log in to this page; instead, the attacker could simply inject an <iframe> pointing to <span class="Apple-style-span" style="font-family:'courier new';">https://example.com/login</span> and use JavaScript to read the password from that frame.</div><div><br /></div><div>Besides checking the page hosting the password field, we can also check where password data is going to be sent when users submit their information. Consider a scenario that occurred a few years ago on a popular social networking site that let users (or in this case, attackers) customize their profile pages. At the time, an attacker could not include JavaScript on his profile page, but could still use malicious HTML — a password field set to send data back to the attacker's web server. When users viewed the attacker's profile, their password managers would automatically fill in their passwords because the profile page was part of the same origin as the site's login page. Lacking JavaScript, the attacker could not read these passwords immediately, but once the users clicked on the page, their data was sent to the attacker's server. Google Chrome defends against this subtle attack by checking the page to which the password data is submitted, once again using the same-origin policy. If this check fails, the password manager will not automatically fill in passwords when the page is loaded. The downside is that this can trip up legitimate web sites that dynamically generate their login URLs. To help users in both cases, the password manager waits for users to type their user names manually before filling in any passwords. At this point, if a page is really malicious, these users have most likely already fallen for the scam and would have proceeded to type in their passwords manually; continuing to refuse to fill in passwords would merely give the impression that the browser is "broken."</div><div><br /></div><div>A number of other proposals to improve password manager security seem reasonable but don't actually make users more secure. For example, the password manager could refuse to supply passwords to invisible login fields, on the theory that legitimate sites have no need to do this and invisible fields are used only by attackers. Unfortunately, attackers trying to hide password fields from users can make the fields visible but only one pixel tall, or 99% transparent, hidden behind another part of the page, or simply scrolled to a position where users don't normally look. It is impossible for browsers to detect all the various ways password fields can be made difficult to notice, so blocking just one doesn't protect users. Plus, a legitimate site might hide the password field initially (similar to Washington Mutual), and if it does, the password manager wouldn't be able to fill in passwords for this site. </div><div><br /></div><div>We've put a lot of thought into the password manager's design and carefully considered how to defend against a number of threats including phishing, cross-site scripting, and HTTPS certificate errors. By using the password manager, you can choose stronger, more complex passwords that are more difficult to remember. When the password manager refuses to automatically fill in your password, you should pause and consider whether you're viewing a spoof web site. We're also keen to improve the compatibility of the password manager. If you're having trouble using the password manager with your favorite site, consider <a href="http://dev.chromium.org/for-testers/bug-reporting-guidelines">filing a bug</a>.</div><div><br /></div><span class="post-author">Posted by Adam Barth and Tim Steele, Software Engineers</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </noscript> </div> </div> <div class='share'> <span class='twitter-custom social-wrapper' data-href='http://twitter.com/share?text=Chromium Blog:Security in Depth: The Password Manager&url=https://blog.chromium.org/2008/12/security-in-depth-password-manager.html&via=ChromiumDev'> <img alt='Share on Twitter' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png' width='24'/> </span> <span class='fb-custom social-wrapper' data-href='https://www.facebook.com/sharer.php?u=https://blog.chromium.org/2008/12/security-in-depth-password-manager.html'> <img alt='Share on Facebook' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png' width='24'/> </span> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://blog.chromium.org/2008/12/security-in-depth-password-manager.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> </div> </div> </div> <div class='post' data-id='5301128915922199039' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2008/12/welcome-pawe-to-team.html' itemprop='url' title='Welcome, Paweł, to the Team'> Welcome, Paweł, to the Team </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Friday, December 12, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <div>Since we open-sourced Chromium, we've had patches contributed from all over the world. Once we published <a href="http://dev.chromium.org/getting-involved/become-a-committer">guidelines</a> on how contributors can become committers, Paweł Hajdan Jr. was the obvious first choice for nomination.</div><div><br /></div><div>Paweł is a computer science student at the University of Warsaw, and in his free time he's managed to write a ton of high-quality code towards making Chromium work on non-Windows platforms. Those of us who have worked on committing his near-daily patches are relieved to see that he'll now be able to commit them himself!</div><div><br /></div><span class="post-author">Posted by Evan Martin, Software Engineer</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <div>Since we open-sourced Chromium, we've had patches contributed from all over the world. Once we published <a href="http://dev.chromium.org/getting-involved/become-a-committer">guidelines</a> on how contributors can become committers, Paweł Hajdan Jr. was the obvious first choice for nomination.</div><div><br /></div><div>Paweł is a computer science student at the University of Warsaw, and in his free time he's managed to write a ton of high-quality code towards making Chromium work on non-Windows platforms. Those of us who have worked on committing his near-daily patches are relieved to see that he'll now be able to commit them himself!</div><div><br /></div><span class="post-author">Posted by Evan Martin, Software Engineer</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </noscript> </div> </div> <div class='share'> <span class='twitter-custom social-wrapper' data-href='http://twitter.com/share?text=Chromium Blog:Welcome, Paweł, to the Team&url=https://blog.chromium.org/2008/12/welcome-pawe-to-team.html&via=ChromiumDev'> <img alt='Share on Twitter' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png' width='24'/> </span> <span class='fb-custom social-wrapper' data-href='https://www.facebook.com/sharer.php?u=https://blog.chromium.org/2008/12/welcome-pawe-to-team.html'> <img alt='Share on Facebook' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png' width='24'/> </span> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://blog.chromium.org/2008/12/welcome-pawe-to-team.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> </div> </div> </div> <div class='post' data-id='4742853519581853718' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2008/12/thanks-for-all-your-help.html' itemprop='url' title='Thanks for all Your Help'> Thanks for all Your Help </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Thursday, December 11, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <div>Today we <a href="http://googleblog.blogspot.com/2008/12/google-chrome-beta.html">announced</a> that with Google Chrome's fifteenth release, we are taking off the "beta" label. We set goals around improving the stability and performance of the browser, and many of you have helped us meet these goals. We are grateful to the many people around the world who have contributed patches to Chromium (we had our first come from Korea after only five hours), the dedicated volunteers who have filed and triaged bugs in our <a href="http://code.google.com/p/chromium/issues/list">issue tracker</a>, the loyal users who braved the sometimes rocky <a href="http://dev.chromium.org/getting-involved/dev-channel">dev channel</a> releases, and everyone who took the simple step of <a href="//www.google.com/support/chrome/bin/answer.py?answer=96817">opting-in</a> to sending usage statistics and crash reports. </div><div><br /></div><div>Google Chrome wouldn't be where it is today without your help. Of course, there's still a ton more to do, so keep the feedback, patches, bug reports, and moral support coming!</div><div><br /></div><span class="post-author">Posted by Ian Fette, Product Manager</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <div>Today we <a href="http://googleblog.blogspot.com/2008/12/google-chrome-beta.html">announced</a> that with Google Chrome's fifteenth release, we are taking off the "beta" label. We set goals around improving the stability and performance of the browser, and many of you have helped us meet these goals. We are grateful to the many people around the world who have contributed patches to Chromium (we had our first come from Korea after only five hours), the dedicated volunteers who have filed and triaged bugs in our <a href="http://code.google.com/p/chromium/issues/list">issue tracker</a>, the loyal users who braved the sometimes rocky <a href="http://dev.chromium.org/getting-involved/dev-channel">dev channel</a> releases, and everyone who took the simple step of <a href="//www.google.com/support/chrome/bin/answer.py?answer=96817">opting-in</a> to sending usage statistics and crash reports. </div><div><br /></div><div>Google Chrome wouldn't be where it is today without your help. Of course, there's still a ton more to do, so keep the feedback, patches, bug reports, and moral support coming!</div><div><br /></div><span class="post-author">Posted by Ian Fette, Product Manager</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </noscript> </div> </div> <div class='share'> <span class='twitter-custom social-wrapper' data-href='http://twitter.com/share?text=Chromium Blog:Thanks for all Your Help&url=https://blog.chromium.org/2008/12/thanks-for-all-your-help.html&via=ChromiumDev'> <img alt='Share on Twitter' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png' width='24'/> </span> <span class='fb-custom social-wrapper' data-href='https://www.facebook.com/sharer.php?u=https://blog.chromium.org/2008/12/thanks-for-all-your-help.html'> <img alt='Share on Facebook' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png' width='24'/> </span> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://blog.chromium.org/2008/12/thanks-for-all-your-help.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> </div> </div> </div> <div class='post' data-id='6076789942490835317' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2008/12/security-in-depth-local-web-pages.html' itemprop='url' title='Security in Depth: Local Web Pages'> Security in Depth: Local Web Pages </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Thursday, December 4, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <div>The foundation of the browser's security model is the <a href="https://developer.mozilla.org/En/Same_origin_policy_for_JavaScript">same-origin policy</a>, which protects web sites from one another. For example, the same-origin policy stops a news site from reading the contents of your Gmail inbox (even if you open both web sites at the same time). But what if a web page comes from your local file system rather than from the Internet? Consider the following hypothetical attack if your browser did not limit the power of local pages:<br /></div><div><br /></div><div><ol><li>You receive an email message from an attacker containing a web page as an attachment, which you download.<br /></li><li>You open the now-local web page in your browser.<br /></li><li>The local web page creates an <span class="Apple-style-span" style="font-family:'courier new';"><iframe></span> whose source is <span class="Apple-style-span" style="font-family: 'courier new';">https://mail.google.com/mail/</span>.<br /></li><li>Because you are logged in to Gmail, the frame loads the messages in your inbox.<br /></li><li>The local web page reads the contents of the frame by using JavaScript to access <span class="Apple-style-span" style="font-family: 'courier new';">frames[0].document.documentElement.innerHTML</span>. (An Internet web page would not be able to perform this step because it would come from a non-Gmail origin; the same-origin policy would cause the read to fail.)<br /></li><li>The local web page places the contents of your inbox into a <span class="Apple-style-span" style="font-family: 'courier new';"><textarea></span> and submits the data via a form POST to the attacker's web server. Now the attacker has your inbox, which may be useful for spamming or identify theft.<br /></li></ol></div><div><br /></div><div>There is nothing Gmail can do to defend itself from this attack. Accordingly, browsers prevent it by making various steps in the above scenario difficult or impossible. To design the best security policy for Google Chrome, we examined the security policies of a number of popular web browsers.</div><div><br /></div><div><ul><li>Safari 3.2. Local web pages in Safari 3.2 are powerful because they can read the contents of any web site (step 5 above succeeds). Safari protects its users by making it difficult for a web page from the Internet to navigate the browser to a local file (step 2 becomes harder). For example, if you click a hyperlink to a local file, Safari won't render the local web page. You have to manually type the file's URL into the location bar or otherwise open the file.<br /></li><li>Internet Explorer 7. Like Safari 3.2, Internet Explorer 7 lets local web pages read arbitrary web sites, and stops web sites from providing hyperlinks to local files. Internet Explorer further mitigates local-file based attacks by stopping local web pages from running JavaScript by default (causing step 5 to fail). Internet Explorer lets users override this restriction by providing a yellow "infobar" that re-enables JavaScript.<br /></li><li>Opera 9.6. Instead of letting local web pages read every web site, Opera 9.6 limits local web pages to reading pages in the local file system (step 5 fails because the <span class="Apple-style-span" style="font-family: 'courier new';"><iframe></span>'s source is non-local). This policy mitigates the most serious attacks, but letting local web pages read local data can still be dangerous if your file system itself contains sensitive information. For example, if you prepare your tax return using your computer, your file system might contain last year's tax return. An attacker could use an attack like the one above to obtain this data.<br /></li><li>Firefox 3. Like Opera, Firefox 3 blocks local web pages from reading Internet pages. Firefox further restricts a local web page to reading only files in the same directory, or a subdirectory. If you view a local web page stored in, say, a "Downloaded Files" directory, it won't be able to read files in "My Documents." Unfortunately, if the local web page is itself located in "My Documents", the page will be able to read your (possibly sensitive) documents.<br /></li></ul></div><div><br /></div><div>When we designed Google Chrome's security policy for local web pages, we chose a design similar to that used by Opera. Google Chrome prevents users from clicking Internet-based hyperlinks to local web pages and blocks local web pages from reading the contents of arbitrary web sites. We chose not to disable JavaScript with an "infobar" override (like Internet Explorer) because most users do not understand the security implications of re-enabling JavaScript and simply re-enable it to make pages work correctly; even those that do understand frequently wish to override the warning, e.g. to develop web pages locally.</div><div><br /></div><div>There is more to the security of local web pages than simply picking an access policy. A sizable number of users have more than one browser installed on their machine. In protecting our users, we also consider "blended" threats that involve more than one browser. For example, you might download a web page in Google Chrome and later open that page in Internet Explorer. To help secure this case, we attach the "<a href="http://msdn.microsoft.com/en-us/library/ms537628%28VS.85%29.aspx">mark of the web</a>" to downloaded web pages. Internet Explorer then treats these pages as if they were on an "unknown" Internet site, which means they can run JavaScript but cannot access the local file system or pages on other Internet sites.</div><div><br /></div><div>Other blended threats are also possible. Consider a user who uses Google Chrome but has Safari set as his or her default browser. When the user downloads a web page with Google Chrome, the page appears in the download tray at the bottom of the browser window. If the user clicks on the downloaded file, Google Chrome will launch the user's default browser (in this case Safari), and Safari will let the page read any web page, bypassing Safari's protections against step 2 in our hypothetical attack. Although this scenario is also possible in other browsers, downloading a file in those browsers requires more steps, making the vector less appealing to attackers. To mitigate this threat, we recently changed Google Chrome to require the user's confirmation when downloading web pages, just as we do for executable files.</div><div><br /></div><div>In the future, we hope to further restrict the privileges of local web pages. We are considering several proposals, including implementing directory-based restrictions (similar to Firefox 3), or preventing local web pages from sending sensitive information back to Internet sites (blocking step 6 above), as proposed by Maciej Stachowiak of the WebKit project. Ultimately, we'd like to see all the browser vendors converge on a uniform, secure policy for local web pages.</div><div><br /></div><span class="post-author">Posted by Adam Barth, Software Engineer</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <div>The foundation of the browser's security model is the <a href="https://developer.mozilla.org/En/Same_origin_policy_for_JavaScript">same-origin policy</a>, which protects web sites from one another. For example, the same-origin policy stops a news site from reading the contents of your Gmail inbox (even if you open both web sites at the same time). But what if a web page comes from your local file system rather than from the Internet? Consider the following hypothetical attack if your browser did not limit the power of local pages:<br /></div><div><br /></div><div><ol><li>You receive an email message from an attacker containing a web page as an attachment, which you download.<br /></li><li>You open the now-local web page in your browser.<br /></li><li>The local web page creates an <span class="Apple-style-span" style="font-family:'courier new';"><iframe></span> whose source is <span class="Apple-style-span" style="font-family: 'courier new';">https://mail.google.com/mail/</span>.<br /></li><li>Because you are logged in to Gmail, the frame loads the messages in your inbox.<br /></li><li>The local web page reads the contents of the frame by using JavaScript to access <span class="Apple-style-span" style="font-family: 'courier new';">frames[0].document.documentElement.innerHTML</span>. (An Internet web page would not be able to perform this step because it would come from a non-Gmail origin; the same-origin policy would cause the read to fail.)<br /></li><li>The local web page places the contents of your inbox into a <span class="Apple-style-span" style="font-family: 'courier new';"><textarea></span> and submits the data via a form POST to the attacker's web server. Now the attacker has your inbox, which may be useful for spamming or identify theft.<br /></li></ol></div><div><br /></div><div>There is nothing Gmail can do to defend itself from this attack. Accordingly, browsers prevent it by making various steps in the above scenario difficult or impossible. To design the best security policy for Google Chrome, we examined the security policies of a number of popular web browsers.</div><div><br /></div><div><ul><li>Safari 3.2. Local web pages in Safari 3.2 are powerful because they can read the contents of any web site (step 5 above succeeds). Safari protects its users by making it difficult for a web page from the Internet to navigate the browser to a local file (step 2 becomes harder). For example, if you click a hyperlink to a local file, Safari won't render the local web page. You have to manually type the file's URL into the location bar or otherwise open the file.<br /></li><li>Internet Explorer 7. Like Safari 3.2, Internet Explorer 7 lets local web pages read arbitrary web sites, and stops web sites from providing hyperlinks to local files. Internet Explorer further mitigates local-file based attacks by stopping local web pages from running JavaScript by default (causing step 5 to fail). Internet Explorer lets users override this restriction by providing a yellow "infobar" that re-enables JavaScript.<br /></li><li>Opera 9.6. Instead of letting local web pages read every web site, Opera 9.6 limits local web pages to reading pages in the local file system (step 5 fails because the <span class="Apple-style-span" style="font-family: 'courier new';"><iframe></span>'s source is non-local). This policy mitigates the most serious attacks, but letting local web pages read local data can still be dangerous if your file system itself contains sensitive information. For example, if you prepare your tax return using your computer, your file system might contain last year's tax return. An attacker could use an attack like the one above to obtain this data.<br /></li><li>Firefox 3. Like Opera, Firefox 3 blocks local web pages from reading Internet pages. Firefox further restricts a local web page to reading only files in the same directory, or a subdirectory. If you view a local web page stored in, say, a "Downloaded Files" directory, it won't be able to read files in "My Documents." Unfortunately, if the local web page is itself located in "My Documents", the page will be able to read your (possibly sensitive) documents.<br /></li></ul></div><div><br /></div><div>When we designed Google Chrome's security policy for local web pages, we chose a design similar to that used by Opera. Google Chrome prevents users from clicking Internet-based hyperlinks to local web pages and blocks local web pages from reading the contents of arbitrary web sites. We chose not to disable JavaScript with an "infobar" override (like Internet Explorer) because most users do not understand the security implications of re-enabling JavaScript and simply re-enable it to make pages work correctly; even those that do understand frequently wish to override the warning, e.g. to develop web pages locally.</div><div><br /></div><div>There is more to the security of local web pages than simply picking an access policy. A sizable number of users have more than one browser installed on their machine. In protecting our users, we also consider "blended" threats that involve more than one browser. For example, you might download a web page in Google Chrome and later open that page in Internet Explorer. To help secure this case, we attach the "<a href="http://msdn.microsoft.com/en-us/library/ms537628%28VS.85%29.aspx">mark of the web</a>" to downloaded web pages. Internet Explorer then treats these pages as if they were on an "unknown" Internet site, which means they can run JavaScript but cannot access the local file system or pages on other Internet sites.</div><div><br /></div><div>Other blended threats are also possible. Consider a user who uses Google Chrome but has Safari set as his or her default browser. When the user downloads a web page with Google Chrome, the page appears in the download tray at the bottom of the browser window. If the user clicks on the downloaded file, Google Chrome will launch the user's default browser (in this case Safari), and Safari will let the page read any web page, bypassing Safari's protections against step 2 in our hypothetical attack. Although this scenario is also possible in other browsers, downloading a file in those browsers requires more steps, making the vector less appealing to attackers. To mitigate this threat, we recently changed Google Chrome to require the user's confirmation when downloading web pages, just as we do for executable files.</div><div><br /></div><div>In the future, we hope to further restrict the privileges of local web pages. We are considering several proposals, including implementing directory-based restrictions (similar to Firefox 3), or preventing local web pages from sending sensitive information back to Internet sites (blocking step 6 above), as proposed by Maciej Stachowiak of the WebKit project. Ultimately, we'd like to see all the browser vendors converge on a uniform, secure policy for local web pages.</div><div><br /></div><span class="post-author">Posted by Adam Barth, Software Engineer</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </noscript> </div> </div> <div class='share'> <span class='twitter-custom social-wrapper' data-href='http://twitter.com/share?text=Chromium Blog:Security in Depth: Local Web Pages&url=https://blog.chromium.org/2008/12/security-in-depth-local-web-pages.html&via=ChromiumDev'> <img alt='Share on Twitter' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png' width='24'/> </span> <span class='fb-custom social-wrapper' data-href='https://www.facebook.com/sharer.php?u=https://blog.chromium.org/2008/12/security-in-depth-local-web-pages.html'> <img alt='Share on Facebook' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png' width='24'/> </span> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://blog.chromium.org/2008/12/security-in-depth-local-web-pages.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> </div> </div> </div> <div class='post' data-id='5049212260693970918' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2008/11/putting-it-to-test.html' itemprop='url' title='Putting It to the Test'> Putting It to the Test </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Friday, November 7, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <div>Historically, testing hasn't gotten much respect in the world of software development.  As the old saying goes, "It compiles! Ship it!" Only a joke — but like most jokes, it hides a grain of truth.<br /></div><div><br /></div><div>Not so for the Chromium project. Our philosophy is to test everything we possibly can, in as many ways as we can think of.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">Test drive: why test?</span></div><div><br /></div><div>It's easy to find arguments against testing. Writing tests takes time that developers could be using to write features, and keeping the test hardware and software infrastructure running smoothly isn't trivial.  (I'm one of the people largely responsible for the latter for Chromium, along with Nicolas Sylvain, so I know how time-consuming it can be.)  But in the long run, it's a big win, for at least two reasons.</div><div><br /></div><div>A well-established set of tests that developers are expected to run before sending changes in makes it a lot easier to avoid causing problems, which lets other developers stay productive rather than chasing down regressions.  And testing submitted changes promptly keeps the code building cleanly and minimizes trouble in the longer term.</div><div><br /></div><div>But even more importantly, an extensive set of automated tests gives us more confidence that Chromium is reliable, stable, and correct.  We're not afraid to rewrite major portions of the code, because verifying correctness afterward is easier. And we have the flexibility to iterate faster and produce releases more often, because we don't need a 6-month QA cycle before each one.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">The test of time: performance testing</span></div><div><br /></div><div>We run a lot of different tests. Tests of security. Tests of UI functionality. Tests of startup time, page-load speed, DOM manipulation, memory usage.  Tests for memory errors using Rational Purify. WebKit's suite of layout tests. Hundreds of unit tests to make sure that individual methods are still doing what they should. At last count, we run more than 9100 individual tests, typically 30-40 times every weekday.<sup>[1]</sup> You can find the <a href="http://dev.chromium.org/developers/testing">full list</a> in the developer documentation, but I'll talk more about one broad category here: performance testing.</div><div><br /></div><div>With every change made in the tree, we keep track of Chromium's page-load time, memory usage, startup time, the time to open a new tab or switch to one, and more.  All these data points are available in graphs like this one:</div><div><br /></div><div><img alt="" border="0" id="BLOGGER_PHOTO_ID_5266021484599531202" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmnK7HXM7hfSxmA61abFoMDTGjG8Hmvf10NOjH6Ka2lBlg9gof6BhN25effx4hNsOZEEXzfLf8QEtMd4nQrrIMDT1fY8NDqb_svlbVNHavU0Pnkf50tmvBwGTJ_lsaFuLML-yqzEqqEuKB/s400/testing_blog_image.png" style="cursor:pointer; cursor:hand;width: 400px; height: 246px;" /><br /></div><div><br /></div><div>Here the top, gold trace shows the startup time on XP for the tip-of-tree build; the green, bottom trace shows the startup time for a reference build so we can discount variation in the test conditions; and the blue, middle trace shows the startup time along a different code path that includes loading gears.dll. The light blue horizontal line is a reference marker. As you can see, whatever changed between the previous build and r3693, it increased the startup time (gold trace) by more than 8%. The developer responsible was able to see that and fix the problem a few builds later.</div><div><br /></div><div>This graph also shows the usefulness of running a reference build. The spike in startup time that lasted only a single build also shows up in the reference-build time (the green trace). We can assume that it was something temporarily affecting the build machine, rather than a code change. (The problem must have cleared up by the time the Gears startup test ran.)</div><div><br /></div><div>With so many performance graphs, it can be hard to watch them all, so there's also a <a href="http://build.chromium.org/buildbot/perf/dashboard/overview.html">summary page</a>.</div><div><br /></div><div>One final note about Chromium's performance graphs: they're written in HTML and JavaScript, and we're looking for someone to make them easier to use.  If you're interested, <a href="http://sites.google.com/a/chromium.org/dev/developers/how-tos/getting-the-buildbot-source">grab the code</a> and <a href="http://dev.chromium.org/developers/contributing-code">start hacking</a>!</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">Test bed: the Chromium buildbot</span></div><div><br /></div><div>Nearly all of this testing is controlled by <a href="http://build.chromium.org/buildbot/waterfall/">Chromium's buildbot</a>, which automates the build/test cycle.  Every time a change is submitted, the buildbot master builds the tree, runs the tests on all the different platforms, and displays the results.  For a complete guide to the buildbot and its "waterfall" result page, see the <a href="http://sites.google.com/a/chromium.org/dev/developers/testing/tour-of-the-chromium-buildbot">Tour of the Chromium Buildbot</a> in the developer docs.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">Pro-test</span></div><div><br /></div><div>Of course, once you have lots of tests running, the second important aspect of good tree hygiene is to keep them all passing.  But that's a subject for another post.</div><div><br /></div><div><span class="Apple-style-span" style="font-style: italic;">[1] It's hard to put a single number on it, because certain tests only apply to some parts of the code.  But however you count it, it's a lot of tests.</span></div><div><br /></div><span class="post-author">Posted by Pamela Greene, Software Engineer</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <div>Historically, testing hasn't gotten much respect in the world of software development.  As the old saying goes, "It compiles! Ship it!" Only a joke — but like most jokes, it hides a grain of truth.<br /></div><div><br /></div><div>Not so for the Chromium project. Our philosophy is to test everything we possibly can, in as many ways as we can think of.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">Test drive: why test?</span></div><div><br /></div><div>It's easy to find arguments against testing. Writing tests takes time that developers could be using to write features, and keeping the test hardware and software infrastructure running smoothly isn't trivial.  (I'm one of the people largely responsible for the latter for Chromium, along with Nicolas Sylvain, so I know how time-consuming it can be.)  But in the long run, it's a big win, for at least two reasons.</div><div><br /></div><div>A well-established set of tests that developers are expected to run before sending changes in makes it a lot easier to avoid causing problems, which lets other developers stay productive rather than chasing down regressions.  And testing submitted changes promptly keeps the code building cleanly and minimizes trouble in the longer term.</div><div><br /></div><div>But even more importantly, an extensive set of automated tests gives us more confidence that Chromium is reliable, stable, and correct.  We're not afraid to rewrite major portions of the code, because verifying correctness afterward is easier. And we have the flexibility to iterate faster and produce releases more often, because we don't need a 6-month QA cycle before each one.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">The test of time: performance testing</span></div><div><br /></div><div>We run a lot of different tests. Tests of security. Tests of UI functionality. Tests of startup time, page-load speed, DOM manipulation, memory usage.  Tests for memory errors using Rational Purify. WebKit's suite of layout tests. Hundreds of unit tests to make sure that individual methods are still doing what they should. At last count, we run more than 9100 individual tests, typically 30-40 times every weekday.<sup>[1]</sup> You can find the <a href="http://dev.chromium.org/developers/testing">full list</a> in the developer documentation, but I'll talk more about one broad category here: performance testing.</div><div><br /></div><div>With every change made in the tree, we keep track of Chromium's page-load time, memory usage, startup time, the time to open a new tab or switch to one, and more.  All these data points are available in graphs like this one:</div><div><br /></div><div><img alt="" border="0" id="BLOGGER_PHOTO_ID_5266021484599531202" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmnK7HXM7hfSxmA61abFoMDTGjG8Hmvf10NOjH6Ka2lBlg9gof6BhN25effx4hNsOZEEXzfLf8QEtMd4nQrrIMDT1fY8NDqb_svlbVNHavU0Pnkf50tmvBwGTJ_lsaFuLML-yqzEqqEuKB/s400/testing_blog_image.png" style="cursor:pointer; cursor:hand;width: 400px; height: 246px;" /><br /></div><div><br /></div><div>Here the top, gold trace shows the startup time on XP for the tip-of-tree build; the green, bottom trace shows the startup time for a reference build so we can discount variation in the test conditions; and the blue, middle trace shows the startup time along a different code path that includes loading gears.dll. The light blue horizontal line is a reference marker. As you can see, whatever changed between the previous build and r3693, it increased the startup time (gold trace) by more than 8%. The developer responsible was able to see that and fix the problem a few builds later.</div><div><br /></div><div>This graph also shows the usefulness of running a reference build. The spike in startup time that lasted only a single build also shows up in the reference-build time (the green trace). We can assume that it was something temporarily affecting the build machine, rather than a code change. (The problem must have cleared up by the time the Gears startup test ran.)</div><div><br /></div><div>With so many performance graphs, it can be hard to watch them all, so there's also a <a href="http://build.chromium.org/buildbot/perf/dashboard/overview.html">summary page</a>.</div><div><br /></div><div>One final note about Chromium's performance graphs: they're written in HTML and JavaScript, and we're looking for someone to make them easier to use.  If you're interested, <a href="http://sites.google.com/a/chromium.org/dev/developers/how-tos/getting-the-buildbot-source">grab the code</a> and <a href="http://dev.chromium.org/developers/contributing-code">start hacking</a>!</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">Test bed: the Chromium buildbot</span></div><div><br /></div><div>Nearly all of this testing is controlled by <a href="http://build.chromium.org/buildbot/waterfall/">Chromium's buildbot</a>, which automates the build/test cycle.  Every time a change is submitted, the buildbot master builds the tree, runs the tests on all the different platforms, and displays the results.  For a complete guide to the buildbot and its "waterfall" result page, see the <a href="http://sites.google.com/a/chromium.org/dev/developers/testing/tour-of-the-chromium-buildbot">Tour of the Chromium Buildbot</a> in the developer docs.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">Pro-test</span></div><div><br /></div><div>Of course, once you have lots of tests running, the second important aspect of good tree hygiene is to keep them all passing.  But that's a subject for another post.</div><div><br /></div><div><span class="Apple-style-span" style="font-style: italic;">[1] It's hard to put a single number on it, because certain tests only apply to some parts of the code.  But however you count it, it's a lot of tests.</span></div><div><br /></div><span class="post-author">Posted by Pamela Greene, Software Engineer</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </noscript> </div> </div> <div class='share'> <span class='twitter-custom social-wrapper' data-href='http://twitter.com/share?text=Chromium Blog:Putting It to the Test&url=https://blog.chromium.org/2008/11/putting-it-to-test.html&via=ChromiumDev'> <img alt='Share on Twitter' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png' width='24'/> </span> <span class='fb-custom social-wrapper' data-href='https://www.facebook.com/sharer.php?u=https://blog.chromium.org/2008/11/putting-it-to-test.html'> <img alt='Share on Facebook' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png' width='24'/> </span> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://blog.chromium.org/2008/11/putting-it-to-test.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> </div> </div> </div> <div class='post' data-id='7642881334954742047' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2008/10/beta-and-plugin-improvements-in-google.html' itemprop='url' title='Beta and Plugin Improvements in Google Chrome'> Beta and Plugin Improvements in Google Chrome </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Thursday, October 30, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <div>After the beta launch in early September, from the first wave of feedback, we realized that a large number of users were facing plugin compatibility issues in Google Chrome. These included Adobe Flash videos not playing, as well as various browser performance issues with Adobe Flash and Adobe PDF document loading. There was even an issue where the browser consumed 100% CPU when users interacted with plugins.</div><div><br /></div><div>This is exactly the kind of feedback we are expecting from a beta launch. We have invested a lot of effort into automating compatibility testing for large number of web pages but there is nothing like actual user feedback. We are impressed by the user response to the beta and the quality of bug reports filed. Nothing more motivating than a lot of users waiting for your work. :) </div><div><br /></div><div>One of the big issues was support for PDF Fast WebView, which is the ability for a webserver to byte serve a PDF document. This allows a client to request specific byte ranges in the file while skipping pages that are not needed. This is supported generically by seekable streams specification in NPAPI, which Google Chrome now implements. This should improve performance with large PDF files or any other content served using Fast WebView.</div><div><br /></div><div>We had a lot of fun fixing other issues too, and here are the stories behind a couple of them. </div><blockquote><div><span class="Apple-style-span" style="font-weight: bold;">YouTube videos stop after six seek attempts:</span></div><div><br /></div><div>We received several reports of YouTube videos failing to play. Many reports indicated that this symptom had something to do with using the slider while playing the video. However, we didn't have a reliable scenario to reproduce in this in-house.</div><div><br /></div><div>Darin Fisher observed that if you move the slider many times, the video stopped playing. Furthermore, he found out that if the slider was moved exactly six times the video would stop playing. This was interesting, because Google Chrome uses a maximum of 6 HTTP connections per host. </div><div><br /></div><div>A quick check of the 'I/O Status' in about:network revealed that all connections were active. The question then became one of why the existing connections weren't canceled when the slider was moved. </div><div><br /></div><div>Darin found that the Flash plugin would return an error when we supplied it data while the slider was moved. In this case a browser is supposed to cancel the connection and that's what fixed it.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">Google Finance chart dragging:</span></div><div><br /></div><div>This report was very interesting, due to the fact that it only occurred on single core machines. Of course, in the end we found out that there wasn't any direct connection between the root cause and single core machines. In Google Chrome plugin windows live in a separate plugin process so a plugin has little or no influence on the browser thread, or so we thought.</div><div><br /></div><div>After some inspection we found out that when a plugin is receiving mouse input, the browser main thread spins with 100% CPU for sometime. Now, the twist to the story is that since a plugin window is a child of the browser window, thread inputs of the browser and the plugin are attached. </div><div><br /></div><div>We started looking at the browser message loop more closely. Soon we discovered that MsgWaitForMultipleObjects/PeekMessage APIs behaved strangely when thread inputs are attached. The MsgWaitForMultipleObjects API is typically used to block until an event or a windows message such as an input is available for processing. In this case, we found that it was returning an indication that an input event was available for processing, while PeekMessage indicated no event was available. </div><div><br /></div><div>This behavior is probably due to the fact that thread inputs are attached and GetQueueStatus, called internally by MsgWaitForMultipleObjects, returned an indication that input is available in the browser thread, while in reality it was intended for the plugin. This caused the MsgWaitForMultipleObjects not do its intended function of waiting, and caused the browser thread to spin.</div></blockquote><div>These are just a few examples of bugfixes we've made to Google Chrome to address performance issues related to plugins. We continue to look closely at the performance of Google Chrome, both as a whole and in relation to interaction with plugins, to make sure that users are getting the best browsing experience that we can deliver.</div><div><br /></div><span class="post-author">Posted by Anantanarayanan Iyengar and Amit Joshi, Software Engineers</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <div>After the beta launch in early September, from the first wave of feedback, we realized that a large number of users were facing plugin compatibility issues in Google Chrome. These included Adobe Flash videos not playing, as well as various browser performance issues with Adobe Flash and Adobe PDF document loading. There was even an issue where the browser consumed 100% CPU when users interacted with plugins.</div><div><br /></div><div>This is exactly the kind of feedback we are expecting from a beta launch. We have invested a lot of effort into automating compatibility testing for large number of web pages but there is nothing like actual user feedback. We are impressed by the user response to the beta and the quality of bug reports filed. Nothing more motivating than a lot of users waiting for your work. :) </div><div><br /></div><div>One of the big issues was support for PDF Fast WebView, which is the ability for a webserver to byte serve a PDF document. This allows a client to request specific byte ranges in the file while skipping pages that are not needed. This is supported generically by seekable streams specification in NPAPI, which Google Chrome now implements. This should improve performance with large PDF files or any other content served using Fast WebView.</div><div><br /></div><div>We had a lot of fun fixing other issues too, and here are the stories behind a couple of them. </div><blockquote><div><span class="Apple-style-span" style="font-weight: bold;">YouTube videos stop after six seek attempts:</span></div><div><br /></div><div>We received several reports of YouTube videos failing to play. Many reports indicated that this symptom had something to do with using the slider while playing the video. However, we didn't have a reliable scenario to reproduce in this in-house.</div><div><br /></div><div>Darin Fisher observed that if you move the slider many times, the video stopped playing. Furthermore, he found out that if the slider was moved exactly six times the video would stop playing. This was interesting, because Google Chrome uses a maximum of 6 HTTP connections per host. </div><div><br /></div><div>A quick check of the 'I/O Status' in about:network revealed that all connections were active. The question then became one of why the existing connections weren't canceled when the slider was moved. </div><div><br /></div><div>Darin found that the Flash plugin would return an error when we supplied it data while the slider was moved. In this case a browser is supposed to cancel the connection and that's what fixed it.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">Google Finance chart dragging:</span></div><div><br /></div><div>This report was very interesting, due to the fact that it only occurred on single core machines. Of course, in the end we found out that there wasn't any direct connection between the root cause and single core machines. In Google Chrome plugin windows live in a separate plugin process so a plugin has little or no influence on the browser thread, or so we thought.</div><div><br /></div><div>After some inspection we found out that when a plugin is receiving mouse input, the browser main thread spins with 100% CPU for sometime. Now, the twist to the story is that since a plugin window is a child of the browser window, thread inputs of the browser and the plugin are attached. </div><div><br /></div><div>We started looking at the browser message loop more closely. Soon we discovered that MsgWaitForMultipleObjects/PeekMessage APIs behaved strangely when thread inputs are attached. The MsgWaitForMultipleObjects API is typically used to block until an event or a windows message such as an input is available for processing. In this case, we found that it was returning an indication that an input event was available for processing, while PeekMessage indicated no event was available. </div><div><br /></div><div>This behavior is probably due to the fact that thread inputs are attached and GetQueueStatus, called internally by MsgWaitForMultipleObjects, returned an indication that input is available in the browser thread, while in reality it was intended for the plugin. This caused the MsgWaitForMultipleObjects not do its intended function of waiting, and caused the browser thread to spin.</div></blockquote><div>These are just a few examples of bugfixes we've made to Google Chrome to address performance issues related to plugins. We continue to look closely at the performance of Google Chrome, both as a whole and in relation to interaction with plugins, to make sure that users are getting the best browsing experience that we can deliver.</div><div><br /></div><span class="post-author">Posted by Anantanarayanan Iyengar and Amit Joshi, Software Engineers</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </noscript> </div> </div> <div class='share'> <span class='twitter-custom social-wrapper' data-href='http://twitter.com/share?text=Chromium Blog:Beta and Plugin Improvements in Google Chrome&url=https://blog.chromium.org/2008/10/beta-and-plugin-improvements-in-google.html&via=ChromiumDev'> <img alt='Share on Twitter' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png' width='24'/> </span> <span class='fb-custom social-wrapper' data-href='https://www.facebook.com/sharer.php?u=https://blog.chromium.org/2008/10/beta-and-plugin-improvements-in-google.html'> <img alt='Share on Facebook' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png' width='24'/> </span> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://blog.chromium.org/2008/10/beta-and-plugin-improvements-in-google.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> </div> </div> </div> <div class='post' data-id='7396106466586573715' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2008/10/graphics-in-google-chrome.html' itemprop='url' title='Graphics in Google Chrome'> Graphics in Google Chrome </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Thursday, October 23, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <div>Google Chrome uses a library called Skia, which is also the graphics engine behind Google's Android mobile OS. The two projects share code that implements WebKit's porting API in terms of Skia. Google Chrome also uses Skia to render parts of the user interface such as the toolbar and tab strip. I'm going to talk about some of the history that led us to choose Skia, as well as how our graphics layer works. <br /></div><div><br /></div><div>WebKit is designed to work on multiple operating systems. It abstracts platform-specific functions into the "port," which an embedder application such as Google Chrome implements specifically for their system. This relatively clean abstraction has helped WebKit to be adopted on a wide variety of devices and systems. One of the parts of the port we had to consider when developing Google Chrome was the graphics layer, which is responsible for rendering text, images, and other graphics to the screen.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">Which graphics library?</span></div><div><br /></div><div>One question that people often ask is, why not use OpenGL or DirectX for accelerated rendering? First, on Windows, we use a sandbox that prevents us from displaying windows from our renderer processes. The image data must be transferred to the main browser process before it can be drawn to the screen, which limits the possible approaches we can take. If the images needs to be read off the video card only to be copied back to the video card in another process, it is usually not worthwhile using accelerated rendering in the first place.</div><div><br /></div><div>Second, drawing graphics is actually a very small percentage of the time we spend rendering a page. Most of the time is spent in WebKit computing where things will be placed, what styles to apply to them, and using system routines to draw text. Accelerated 3D graphics would not give us enough overall improvement in speed to balance out the extra work and compatibility problems that we would encounter.</div><div><br /></div><div>If we aren't going to be using OpenGL or DirectX, what about other graphics libraries? We considered a number of options when we first started work on our Windows port of WebKit:</div><div><ul><li><a href="http://msdn.microsoft.com/en-us/library/ms536795(VS.85).aspx">Windows GDI</a>: GDI is the basic, low-level graphics API in Microsoft Windows. It is used to draw buttons, window controls, and dialog boxes for every Windows application, so we know that it's tested and works well. However, it has relatively basic capabilities. Although most web pages can be drawn using only these basic primitives, parts of <canvas> or SVG would need to be implemented separately, either using a different graphics library, or our own custom code.</li><li><a href="http://msdn.microsoft.com/en-us/library/ms533798(VS.85).aspx">GDI</a>+: GDI+ is a more advanced graphics API provided on newer versions of Windows. Its API is cleaner and it supports most 2D graphics operations you could think to use. However, we had concerns about GDI+ using device independent metrics, which means that text and letter spacing might look different in Google Chrome than in other Windows applications (which measure and draw text tailored to the screen device). Additionally, at the time we were making the decision, Microsoft was recommending developers use newer graphics APIs in Windows, so we weren't sure how much longer GDI+ would be supported and maintained.</li><li><a href="http://www.cairographics.org/">Cairo</a>: Cairo is an open-source 2D graphics library. It is successfully used in Firefox 3, and the Windows port of WebKit at that time already had a partially complete graphics implementation for WebKit. Cairo is also cross-platform, a key advantage over GDI and GDI+ when building a cross-platform browser.</li></ul></div><div>We ended up choosing Skia over these options because it is cross-platform (meaning our work wouldn't have to be duplicated when porting to other systems), because there was already a high-quality WebKit port using it created for Android's browser, and because we had in-house expertise. The latter point is critical because we expected to (and did) need additional features added to the graphics library as well as some bugs fixed.</div><div><br /></div><div>So far, we've been very happy with our choice. Skia has proved to be effective at handling all the graphics operations we've needed, has been fast enough despite being software-only, and we've gotten great support from the Skia team. Thanks!</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">System-specific features</span></div><div><br /></div><div>Android has the advantage of controlling the entire operating system graphics layer. Skia's font layer implements all text rendering for the Android system, so all text looks consistent. However, we wanted to match the host OS's look and feel. This means using native text rendering routines so that, for example, we can get <a href="http://www.microsoft.com/typography/whatiscleartype.mspx">ClearType</a> on Windows.</div><div><br /></div><div>To solve this problem, we create a wrapper around Skia's SkDevice (an object representing a low-level drawing surface) which we call PlatformDevice. The object is both a bitmap in main memory that Skia can draw into, and a "Device Independent Bitmap" that the Windows GDI layer can draw into. Lines, images, and patters are all drawn by Skia into this bitmap, while text is drawn directly by Windows. As part of our porting efforts, we are currently working on creating similar abstractions for OS X and Linux.</div><div><br /></div><span class="post-author">Posted by Brett Wilson, Software Engineer</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <div>Google Chrome uses a library called Skia, which is also the graphics engine behind Google's Android mobile OS. The two projects share code that implements WebKit's porting API in terms of Skia. Google Chrome also uses Skia to render parts of the user interface such as the toolbar and tab strip. I'm going to talk about some of the history that led us to choose Skia, as well as how our graphics layer works. <br /></div><div><br /></div><div>WebKit is designed to work on multiple operating systems. It abstracts platform-specific functions into the "port," which an embedder application such as Google Chrome implements specifically for their system. This relatively clean abstraction has helped WebKit to be adopted on a wide variety of devices and systems. One of the parts of the port we had to consider when developing Google Chrome was the graphics layer, which is responsible for rendering text, images, and other graphics to the screen.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">Which graphics library?</span></div><div><br /></div><div>One question that people often ask is, why not use OpenGL or DirectX for accelerated rendering? First, on Windows, we use a sandbox that prevents us from displaying windows from our renderer processes. The image data must be transferred to the main browser process before it can be drawn to the screen, which limits the possible approaches we can take. If the images needs to be read off the video card only to be copied back to the video card in another process, it is usually not worthwhile using accelerated rendering in the first place.</div><div><br /></div><div>Second, drawing graphics is actually a very small percentage of the time we spend rendering a page. Most of the time is spent in WebKit computing where things will be placed, what styles to apply to them, and using system routines to draw text. Accelerated 3D graphics would not give us enough overall improvement in speed to balance out the extra work and compatibility problems that we would encounter.</div><div><br /></div><div>If we aren't going to be using OpenGL or DirectX, what about other graphics libraries? We considered a number of options when we first started work on our Windows port of WebKit:</div><div><ul><li><a href="http://msdn.microsoft.com/en-us/library/ms536795(VS.85).aspx">Windows GDI</a>: GDI is the basic, low-level graphics API in Microsoft Windows. It is used to draw buttons, window controls, and dialog boxes for every Windows application, so we know that it's tested and works well. However, it has relatively basic capabilities. Although most web pages can be drawn using only these basic primitives, parts of <canvas> or SVG would need to be implemented separately, either using a different graphics library, or our own custom code.</li><li><a href="http://msdn.microsoft.com/en-us/library/ms533798(VS.85).aspx">GDI</a>+: GDI+ is a more advanced graphics API provided on newer versions of Windows. Its API is cleaner and it supports most 2D graphics operations you could think to use. However, we had concerns about GDI+ using device independent metrics, which means that text and letter spacing might look different in Google Chrome than in other Windows applications (which measure and draw text tailored to the screen device). Additionally, at the time we were making the decision, Microsoft was recommending developers use newer graphics APIs in Windows, so we weren't sure how much longer GDI+ would be supported and maintained.</li><li><a href="http://www.cairographics.org/">Cairo</a>: Cairo is an open-source 2D graphics library. It is successfully used in Firefox 3, and the Windows port of WebKit at that time already had a partially complete graphics implementation for WebKit. Cairo is also cross-platform, a key advantage over GDI and GDI+ when building a cross-platform browser.</li></ul></div><div>We ended up choosing Skia over these options because it is cross-platform (meaning our work wouldn't have to be duplicated when porting to other systems), because there was already a high-quality WebKit port using it created for Android's browser, and because we had in-house expertise. The latter point is critical because we expected to (and did) need additional features added to the graphics library as well as some bugs fixed.</div><div><br /></div><div>So far, we've been very happy with our choice. Skia has proved to be effective at handling all the graphics operations we've needed, has been fast enough despite being software-only, and we've gotten great support from the Skia team. Thanks!</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">System-specific features</span></div><div><br /></div><div>Android has the advantage of controlling the entire operating system graphics layer. Skia's font layer implements all text rendering for the Android system, so all text looks consistent. However, we wanted to match the host OS's look and feel. This means using native text rendering routines so that, for example, we can get <a href="http://www.microsoft.com/typography/whatiscleartype.mspx">ClearType</a> on Windows.</div><div><br /></div><div>To solve this problem, we create a wrapper around Skia's SkDevice (an object representing a low-level drawing surface) which we call PlatformDevice. The object is both a bitmap in main memory that Skia can draw into, and a "Device Independent Bitmap" that the Windows GDI layer can draw into. Lines, images, and patters are all drawn by Skia into this bitmap, while text is drawn directly by Windows. As part of our porting efforts, we are currently working on creating similar abstractions for OS X and Linux.</div><div><br /></div><span class="post-author">Posted by Brett Wilson, Software Engineer</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </noscript> </div> </div> <div class='share'> <span class='twitter-custom social-wrapper' data-href='http://twitter.com/share?text=Chromium Blog:Graphics in Google Chrome&url=https://blog.chromium.org/2008/10/graphics-in-google-chrome.html&via=ChromiumDev'> <img alt='Share on Twitter' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png' width='24'/> </span> <span class='fb-custom social-wrapper' data-href='https://www.facebook.com/sharer.php?u=https://blog.chromium.org/2008/10/graphics-in-google-chrome.html'> <img alt='Share on Facebook' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png' width='24'/> </span> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://blog.chromium.org/2008/10/graphics-in-google-chrome.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> </div> </div> </div> <div class='post' data-id='2717142420307972014' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2008/10/content-not-chrome.html' itemprop='url' title='Content, not 'Chrome''> Content, not 'Chrome' </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Wednesday, October 15, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <div>In user-experience lingo, 'chrome' refers to the frame of an application - the toolbars, titlebars and buttons that surround your primary content. In Google Chrome, we strove to eliminate as much of this as possible - not just because it leads to a simpler, cleaner design, but because we felt that your web applications should not appear to be constrained within the bulky cruft of a browser - they should feel like first-class applications on your desktop. </div><div><br /></div><div>This notion of "content, not chrome" was the mostly-quiet, sometimes-loud guiding principle behind our design; in combination with our tab-dragging work, it lead us to think of Google Chrome as a lightweight, tabbed window manager for the web. You may have noticed, for example, that Google Chrome doesn't use the traditional "browser titlebar - navigation toolbar - tabstrip" layout common in browsers today; in the Google Chrome world, we think of tabs as the equivalent of titlebars for web pages, and they deserve top-level placement and prominence, and should be the container for everything related to them - title, toolbar and content.</div><div><br /></div><div>To achieve the streamlined feel we were after, we knew we would have to cut some things, and while we had our own intuitions about what was and wasn't useful in current browsers, we had no idea how those ideas matched to reality. So in typical Google fashion, we turned to data; we ran long studies of the browsing habits of thousands of volunteers, compiled giant charts of what features people did and didn't use, argued over and incorporated that data into our designs and prototypes, ran experiments, watched how our test users reacted, listened to their feedback, and then repeated the cycle over and over and over again.</div><div><br /></div><div>Even the the more subtle parts of our first-level UI were subjected to similarly intense scrutiny - "what shade of blue best suits XP users", "should the tabs start 18 or 19 pixels below the top of the window?", "what's the correct offset between our buttons?". The answers to these questions were debated and tested for our entire development cycle, and we saw that opinions consistently differed greatly depending on whether we had been Windows 3.1, OS7 or even NeXT users and developers.</div><div><br /></div><div>We realize that browser UI is controversial and that despite our data-driven approach, much of it remains subjective, so we've documented many of the major UI decisions and thought processes behind Google Chrome on our <a href="http://dev.chromium.org/user-experience">UX Site</a>, we encourage you to read about our work, challenge our assumptions, and let us know how you think things could be improved.</div><div><br /></div><span class="post-author">Posted by Glen Murphy, Software Engineer</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <div>In user-experience lingo, 'chrome' refers to the frame of an application - the toolbars, titlebars and buttons that surround your primary content. In Google Chrome, we strove to eliminate as much of this as possible - not just because it leads to a simpler, cleaner design, but because we felt that your web applications should not appear to be constrained within the bulky cruft of a browser - they should feel like first-class applications on your desktop. </div><div><br /></div><div>This notion of "content, not chrome" was the mostly-quiet, sometimes-loud guiding principle behind our design; in combination with our tab-dragging work, it lead us to think of Google Chrome as a lightweight, tabbed window manager for the web. You may have noticed, for example, that Google Chrome doesn't use the traditional "browser titlebar - navigation toolbar - tabstrip" layout common in browsers today; in the Google Chrome world, we think of tabs as the equivalent of titlebars for web pages, and they deserve top-level placement and prominence, and should be the container for everything related to them - title, toolbar and content.</div><div><br /></div><div>To achieve the streamlined feel we were after, we knew we would have to cut some things, and while we had our own intuitions about what was and wasn't useful in current browsers, we had no idea how those ideas matched to reality. So in typical Google fashion, we turned to data; we ran long studies of the browsing habits of thousands of volunteers, compiled giant charts of what features people did and didn't use, argued over and incorporated that data into our designs and prototypes, ran experiments, watched how our test users reacted, listened to their feedback, and then repeated the cycle over and over and over again.</div><div><br /></div><div>Even the the more subtle parts of our first-level UI were subjected to similarly intense scrutiny - "what shade of blue best suits XP users", "should the tabs start 18 or 19 pixels below the top of the window?", "what's the correct offset between our buttons?". The answers to these questions were debated and tested for our entire development cycle, and we saw that opinions consistently differed greatly depending on whether we had been Windows 3.1, OS7 or even NeXT users and developers.</div><div><br /></div><div>We realize that browser UI is controversial and that despite our data-driven approach, much of it remains subjective, so we've documented many of the major UI decisions and thought processes behind Google Chrome on our <a href="http://dev.chromium.org/user-experience">UX Site</a>, we encourage you to read about our work, challenge our assumptions, and let us know how you think things could be improved.</div><div><br /></div><span class="post-author">Posted by Glen Murphy, Software Engineer</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </noscript> </div> </div> <div class='share'> <span class='twitter-custom social-wrapper' data-href='http://twitter.com/share?text=Chromium Blog:Content, not 'Chrome'&url=https://blog.chromium.org/2008/10/content-not-chrome.html&via=ChromiumDev'> <img alt='Share on Twitter' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png' width='24'/> </span> <span class='fb-custom social-wrapper' data-href='https://www.facebook.com/sharer.php?u=https://blog.chromium.org/2008/10/content-not-chrome.html'> <img alt='Share on Facebook' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png' width='24'/> </span> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://blog.chromium.org/2008/10/content-not-chrome.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> </div> </div> </div> <div class='post' data-id='6385185659584280038' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2008/10/responsiveness-for-plugins-and-renderer.html' itemprop='url' title='Responsiveness for Plugins and the Renderer'> Responsiveness for Plugins and the Renderer </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Friday, October 10, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <div>In my last post, I wrote about how we handle I/O in the browser process to keep the main thread of Google Chrome free from hiccups. This time, I'll write about how we keep our sub-processes from interfering with the main ("browser") process.</div><div><br /></div><div>As you may recall, Google Chrome is a multi-process application, with HTML rendering happening in separate processes we call the "renderers," and plugins running in separate "plugin" processes. Our priority is to always keep the browser process, and especially its main thread, running as smoothly as possible. If a plugin or renderer is interfering with the browser process, the user's interaction with all other tabs and plugins, as well as all the other features of Google Chrome, would also be interrupted. The user might even be prevented from terminating the offending sub-process, negating a key benefit of our multi-process architecture.</div><div><br /></div><div>The first and most obvious approach is never to block while waiting for information from a renderer process, in case the renderer process happens to be busy or hung. And although the renderers may sometimes synchronously wait for the browser for some requests, there is not an easy way to express that the browser process should wait for the renderer on Windows. Unfortunately, this doesn't cover all cases.</div><div><br /></div><div>The basic primitive of Microsoft Windows is the "window," which is much more general than just a top-level window with a title bar. Buttons, toolbars, and text controls are usually expressed as sub-windows of a floating top-level window. Windows in this hierarchy are not restricted to single processes, and early versions of Google Chrome used this feature to implement our cross-process rendering architecture. Each tab contained a sub-window owned by a renderer process. The renderer received input and painted into its child window just like any other. The browser and renderer processes each ran their own message processing for things like painting.</div><div><br /></div><div>A problem arises for some types of Windows messages. The system will synchronously send them to all windows in a hierarchy, waiting for each window to process the message before sending it to parent or child windows. This introduces an implicit wait in the browser process on the renderer processes. If a renderer is hung and not responding to messages, the browser process will also hang as soon as one of these special messages is received. To solve this problem, we no longer allow the renderers to create any windows. Instead, the renderer paints the web page into an off-screen bitmap and sends it asynchronously to the browser process where it is copied to the screen.</div><div><br /></div><div>Once we made this change, everything ran great. That is, until we implemented plugins. The NPAPI plugin standard that Google Chrome implements allows plugins to create sub-windows, and for compatibility, we can't avoid it. Sometimes a plugin may hang, or more commonly, block waiting on disk I/O. All the hard work we did to insulate the user interface from I/O latency is occasionally undone by our plugin architecture through this long chain of dependencies. To mitigate this problem, we periodically check plugins for responsiveness. If a plugin is unresponsive for too long, we know that the user-interface of Google Chrome might also be affected, and the user might not even be able to close the page that is hosting the plugin. To allow the user to regain control of the browser, we pop up a dialog that offers to terminate the plugin.</div><div><br /></div><div>If you are doing something that saturates your hard drive (such as compiling Google Chrome), now you know one of the reasons why the interface may occasionally hang and give the "hung plugin" dialog box. Sometimes you may not even realize that a page has loaded plugins when you get this message. You can terminate the plugin immediately, but most of the time it also works to just wait longer for the plugin's I/O to complete.</div><div><br /></div><span class="post-author">Posted by Brett Wilson, Software Engineer</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <div>In my last post, I wrote about how we handle I/O in the browser process to keep the main thread of Google Chrome free from hiccups. This time, I'll write about how we keep our sub-processes from interfering with the main ("browser") process.</div><div><br /></div><div>As you may recall, Google Chrome is a multi-process application, with HTML rendering happening in separate processes we call the "renderers," and plugins running in separate "plugin" processes. Our priority is to always keep the browser process, and especially its main thread, running as smoothly as possible. If a plugin or renderer is interfering with the browser process, the user's interaction with all other tabs and plugins, as well as all the other features of Google Chrome, would also be interrupted. The user might even be prevented from terminating the offending sub-process, negating a key benefit of our multi-process architecture.</div><div><br /></div><div>The first and most obvious approach is never to block while waiting for information from a renderer process, in case the renderer process happens to be busy or hung. And although the renderers may sometimes synchronously wait for the browser for some requests, there is not an easy way to express that the browser process should wait for the renderer on Windows. Unfortunately, this doesn't cover all cases.</div><div><br /></div><div>The basic primitive of Microsoft Windows is the "window," which is much more general than just a top-level window with a title bar. Buttons, toolbars, and text controls are usually expressed as sub-windows of a floating top-level window. Windows in this hierarchy are not restricted to single processes, and early versions of Google Chrome used this feature to implement our cross-process rendering architecture. Each tab contained a sub-window owned by a renderer process. The renderer received input and painted into its child window just like any other. The browser and renderer processes each ran their own message processing for things like painting.</div><div><br /></div><div>A problem arises for some types of Windows messages. The system will synchronously send them to all windows in a hierarchy, waiting for each window to process the message before sending it to parent or child windows. This introduces an implicit wait in the browser process on the renderer processes. If a renderer is hung and not responding to messages, the browser process will also hang as soon as one of these special messages is received. To solve this problem, we no longer allow the renderers to create any windows. Instead, the renderer paints the web page into an off-screen bitmap and sends it asynchronously to the browser process where it is copied to the screen.</div><div><br /></div><div>Once we made this change, everything ran great. That is, until we implemented plugins. The NPAPI plugin standard that Google Chrome implements allows plugins to create sub-windows, and for compatibility, we can't avoid it. Sometimes a plugin may hang, or more commonly, block waiting on disk I/O. All the hard work we did to insulate the user interface from I/O latency is occasionally undone by our plugin architecture through this long chain of dependencies. To mitigate this problem, we periodically check plugins for responsiveness. If a plugin is unresponsive for too long, we know that the user-interface of Google Chrome might also be affected, and the user might not even be able to close the page that is hosting the plugin. To allow the user to regain control of the browser, we pop up a dialog that offers to terminate the plugin.</div><div><br /></div><div>If you are doing something that saturates your hard drive (such as compiling Google Chrome), now you know one of the reasons why the interface may occasionally hang and give the "hung plugin" dialog box. Sometimes you may not even realize that a page has loaded plugins when you get this message. You can terminate the plugin immediately, but most of the time it also works to just wait longer for the plugin's I/O to complete.</div><div><br /></div><span class="post-author">Posted by Brett Wilson, Software Engineer</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </noscript> </div> </div> <div class='share'> <span class='twitter-custom social-wrapper' data-href='http://twitter.com/share?text=Chromium Blog:Responsiveness for Plugins and the Renderer&url=https://blog.chromium.org/2008/10/responsiveness-for-plugins-and-renderer.html&via=ChromiumDev'> <img alt='Share on Twitter' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png' width='24'/> </span> <span class='fb-custom social-wrapper' data-href='https://www.facebook.com/sharer.php?u=https://blog.chromium.org/2008/10/responsiveness-for-plugins-and-renderer.html'> <img alt='Share on Facebook' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png' width='24'/> </span> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://blog.chromium.org/2008/10/responsiveness-for-plugins-and-renderer.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> </div> </div> </div> <div class='post' data-id='4862304960851437745' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2008/10/io-in-google-chrome.html' itemprop='url' title='I/O in Google Chrome'> I/O in Google Chrome </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Wednesday, October 8, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <div>One of our early goals for Google Chrome was to make the browser as fast as we possibly could. But in addition to raw speed, we wanted it to be highly responsive. After all, it doesn't matter how fast pages can be loaded if the user interface is locked up!</div><div><br /></div><div>To understand our holistic approach to performance in Google Chrome, it helps to know some background. Processing speed per dollar has rapidly increased over the last 40 years, but hard drives, which are based on moving parts, do not improve nearly as fast. As a result, a modern processor can execute millions of instructions in the same time that it takes to read just one byte off disk. We knew that building a fast, responsive browser for modern systems would require extra attention to disk I/O usage.</div><div><br /></div><div>Developers are ideal testers for I/O performance since the load of compiling a very large application like Google Chrome will bog down even the most powerful system. This soon led us to a rule that the main thread of Google Chrome—the thread that runs the entire user interface—is not allowed to do any I/O. After fixing the obvious cases, we ran a program that thrashes the disk while we profiled common operations in Google Chrome to find latent I/O hotspots. We even ran a test where we removed the privileges of the main thread to read or write to disk, and made sure that nothing stopped working.</div><div><br /></div><div>We moved the I/O onto a number of background threads which allow the user-interface to proceed asynchronously. We did this for large data sources like cookies, bookmarks, and the cache, and also for a myriad of smaller things. Writing a downloaded file to disk, or getting the icons for files in the download manager? The disk operations are being called from a special background thread. Indexing the contents of pages in history or saving a login password? All from background threads. Even the "Save As" dialog box is run from another thread because it can momentarily hang the application while it populates.</div><div><br /></div><div>Startup poses a different type of problem. If all the subsystems simultaneously requested their data on startup, even if it was from different threads, the requests would quickly overwhelm the disk. As a result, we delay loading as much data as possible for as long as possible, so the most important work can get done first.</div><div><br /></div><div>Our startup sequence works like this: First chrome.exe and chrome.dll are loaded. Then the preferences file is loaded (it may affect how things proceed). Then we immediately display the main window. The user now can interact with the UI and feels like Google Chrome has loaded, even though there has been remarkably little work done. Immediately after showing the window, we create the sub-process for rendering the first tab. Only once this process has loaded do subsystems like bookmarks proceed, since any I/O contention would slow down the display of that first tab (this is why you may see things like your bookmarks appear after a slight delay). The cache, cookies, and the Windows networking libraries are not loaded until even later when the first network request is issued.</div><div><br /></div><div>We carefully monitor startup performance using an automated test that runs for almost every change to the code. This test was created very early in the project, when Google Chrome did almost nothing, and we have always followed a very simple rule: this test can never get any slower. Because it's much easier to address performance problems as they are created than fixing them later, we are quick to fix or revert any regressions. As a result, our very large application starts as fast today as the very lightweight application we started out with.</div><div><br /></div><div>Our work on I/O performance sometimes complicates the code because so many operations have to be designed to be asynchronous: managing requests on different threads with data that comes in at different times is a lot of extra work. But we think it has been well worth it to help us achieve our goal of making Google Chrome not only the fastest, but the most responsive browser we could build.</div><div><br /></div><span class="post-author">Posted by Brett Wilson, Software Engineer</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <div>One of our early goals for Google Chrome was to make the browser as fast as we possibly could. But in addition to raw speed, we wanted it to be highly responsive. After all, it doesn't matter how fast pages can be loaded if the user interface is locked up!</div><div><br /></div><div>To understand our holistic approach to performance in Google Chrome, it helps to know some background. Processing speed per dollar has rapidly increased over the last 40 years, but hard drives, which are based on moving parts, do not improve nearly as fast. As a result, a modern processor can execute millions of instructions in the same time that it takes to read just one byte off disk. We knew that building a fast, responsive browser for modern systems would require extra attention to disk I/O usage.</div><div><br /></div><div>Developers are ideal testers for I/O performance since the load of compiling a very large application like Google Chrome will bog down even the most powerful system. This soon led us to a rule that the main thread of Google Chrome—the thread that runs the entire user interface—is not allowed to do any I/O. After fixing the obvious cases, we ran a program that thrashes the disk while we profiled common operations in Google Chrome to find latent I/O hotspots. We even ran a test where we removed the privileges of the main thread to read or write to disk, and made sure that nothing stopped working.</div><div><br /></div><div>We moved the I/O onto a number of background threads which allow the user-interface to proceed asynchronously. We did this for large data sources like cookies, bookmarks, and the cache, and also for a myriad of smaller things. Writing a downloaded file to disk, or getting the icons for files in the download manager? The disk operations are being called from a special background thread. Indexing the contents of pages in history or saving a login password? All from background threads. Even the "Save As" dialog box is run from another thread because it can momentarily hang the application while it populates.</div><div><br /></div><div>Startup poses a different type of problem. If all the subsystems simultaneously requested their data on startup, even if it was from different threads, the requests would quickly overwhelm the disk. As a result, we delay loading as much data as possible for as long as possible, so the most important work can get done first.</div><div><br /></div><div>Our startup sequence works like this: First chrome.exe and chrome.dll are loaded. Then the preferences file is loaded (it may affect how things proceed). Then we immediately display the main window. The user now can interact with the UI and feels like Google Chrome has loaded, even though there has been remarkably little work done. Immediately after showing the window, we create the sub-process for rendering the first tab. Only once this process has loaded do subsystems like bookmarks proceed, since any I/O contention would slow down the display of that first tab (this is why you may see things like your bookmarks appear after a slight delay). The cache, cookies, and the Windows networking libraries are not loaded until even later when the first network request is issued.</div><div><br /></div><div>We carefully monitor startup performance using an automated test that runs for almost every change to the code. This test was created very early in the project, when Google Chrome did almost nothing, and we have always followed a very simple rule: this test can never get any slower. Because it's much easier to address performance problems as they are created than fixing them later, we are quick to fix or revert any regressions. As a result, our very large application starts as fast today as the very lightweight application we started out with.</div><div><br /></div><div>Our work on I/O performance sometimes complicates the code because so many operations have to be designed to be asynchronous: managing requests on different threads with data that comes in at different times is a lot of extra work. But we think it has been well worth it to help us achieve our goal of making Google Chrome not only the fastest, but the most responsive browser we could build.</div><div><br /></div><span class="post-author">Posted by Brett Wilson, Software Engineer</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </noscript> </div> </div> <div class='share'> <span class='twitter-custom social-wrapper' data-href='http://twitter.com/share?text=Chromium Blog:I/O in Google Chrome&url=https://blog.chromium.org/2008/10/io-in-google-chrome.html&via=ChromiumDev'> <img alt='Share on Twitter' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png' width='24'/> </span> <span class='fb-custom social-wrapper' data-href='https://www.facebook.com/sharer.php?u=https://blog.chromium.org/2008/10/io-in-google-chrome.html'> <img alt='Share on Facebook' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png' width='24'/> </span> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://blog.chromium.org/2008/10/io-in-google-chrome.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> </div> </div> </div> <div class='post' data-id='4089007954049647770' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2008/10/new-approach-to-browser-security-google.html' itemprop='url' title='A new approach to browser security: the Google Chrome Sandbox'> A new approach to browser security: the Google Chrome Sandbox </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Thursday, October 2, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <div>Building a secure browser is a top priority for the Chromium team; it's why we spend a lot of time and effort keeping our code secure. But as you can imagine, code perfection is something almost impossible to achieve for a project of this size and complexity. To make things worse, a browser spends most of its time handling and executing untrusted and potentially malicious input data. In the event that something goes wrong, the team has developed a sandbox to help thwart any exploit in two of the most popular vectors of attack against browsers: HTML Rendering and JavaScript execution.</div><div><br /></div><div>In a nutshell, a sandbox is security mechanism used to run an application in a restricted environment. If an attacker is able to exploit the browser in a way that lets him run arbitrary code on the machine, the sandbox would help prevent this code from causing damage to the system. The sandbox would also help prevent this exploit from modifying and even reading your files or any information on the system.</div><div><br /></div><div>We are very excited to be able to launch Google Chrome with the sandbox enabled on all the platforms we currently support. Even though the sandbox in Google Chrome uses some of the new security features on Windows Vista, it is fully compatible with Windows XP.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">What part of chromium is sandboxed?</span></div><div><br /></div><div>Google Chrome's <a href="http://blog.chromium.org/2008/09/multi-process-architecture.html">multi process architecture</a> allows for a lot of flexibility in the way we do security. The entire HTML rendering and JavaScript execution is isolated to its own class of processes; the renderers. These are the ones that live in the sandbox. We expect to work in the near future with the plug-in vendors to securely sandbox them as well. </div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">How does the sandbox work?</span></div><div><br /></div><div>The sandbox uses the security features of Windows extensively; it does not reinvent any security model.</div><div><br /></div><div>To understand how it works, one needs a basic understanding of the Windows security model. With this model all processes have an <span class="Apple-style-span" style="font-style: italic;">access token</span>. This access token is like an ID card, it contains information about the owner of the process, the list of groups that it belongs to and a list of privileges. Each process has its own token, and the system uses it to deny or grant access to resources. </div><div><br /></div><div>These resources are called <span class="Apple-style-span" style="font-style: italic;">securable objects</span>. They are securable because they are associated with an access control list, or <span class="Apple-style-span" style="font-style: italic;">security descriptor</span>. It contains the security settings of the object. The list of all the users and groups having access to the resource, and what kind of access they have (read, write, execute, etc) can be found there. Files, registry keys, mutexes, pipes, events, semaphores are examples of securable objects.</div><div><br /></div><div>The <span class="Apple-style-span" style="font-style: italic;">access check</span> is the mechanism by which the system determines whether the security descriptor of an object grants the rights requested to an access token. It is performed every time a process tries to acquire a securable object.</div><div><br /></div><div>The process access token is almost entirely customizable. It's possible to remove privileges and disable some groups. This is exactly what the sandbox does. </div><div><br /></div><div>Before launching the renderer process we modify its token to remove all privileges and disable all groups. We then convert the token to a restricted token. A restricted token is like a normal token, but the access checks are performed twice, the first time with the normal information in the token, and the second one using a secondary list of groups. Both access checks have to succeed for the resources to be granted to the process. Google Chrome sets the secondary list of groups to contain only one item, the NULL user. Since this user is never given permissions to any objects, all access checks performed with the access token of the renderer process fail, making this process useless to an attacker.</div><div><br /></div><div>Of course, not all resources on Windows follow this security model. The keyboard, the mouse, the screen and some user objects, like cursors, icons and windows are examples of resources that don't have security descriptors. There is no access check performed when trying to access them. To prevent the renderer from accessing those, the sandbox uses a combination of Job Objects and alternate desktops. A job object is used to apply some restrictions on a group of processes. Some of the restrictions we apply on the renderer process include accessing windows created outside the job, reading or writing to the clipboard, and exiting Windows. We also used an alternate desktop to prevent the renderer from seeing the screen (screen scrapping) or eavesdropping on the keyboard and mouse (key logging). Alternate desktops are commonly used for security. For example, on Windows, the login screen is on another desktop. It ensures that your password can't be stolen by applications running on your normal desktop.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">What are the limitations?</span></div><div><br /></div><div>As we said earlier, the sandbox itself is not a new security model; it relies on Windows to achieve its security. Therefore, it is impossible for us to prevent against a flaw in the OS security model itself. In addition, some legacy file systems, like FAT32, used on certain computers and USB keys don't support security descriptors. Files on these devices can't be protected by the sandbox. Finally, some third party vendors mistakenly configure files, registry keys and other objects in a way that bypasses the access check, giving everyone on the machine full access on them. Unfortunately, it's impossible for the sandbox to protect most of these misconfigured resources.</div><div><br /></div><div>To conclude, it is important to mention that this sandbox was designed to be generic. It is not tied to Google Chrome. It can easily be used by any other projects with a compatible multi-process architecture. You can find more information about the sandbox in the <a href="http://dev.chromium.org/developers/design-documents/sandbox">design doc</a>, and we will post here again about the details of our token manipulation and our policy framework to configure the level of security of the sandbox.</div><div><br /></div><div>We hope you will feel safe browsing the web using Google Chrome, and we are looking forward to your feedback and code contribution!</div><div><br /></div><span class="post-author">Posted by Nicolas Sylvain, Software Engineer</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <div>Building a secure browser is a top priority for the Chromium team; it's why we spend a lot of time and effort keeping our code secure. But as you can imagine, code perfection is something almost impossible to achieve for a project of this size and complexity. To make things worse, a browser spends most of its time handling and executing untrusted and potentially malicious input data. In the event that something goes wrong, the team has developed a sandbox to help thwart any exploit in two of the most popular vectors of attack against browsers: HTML Rendering and JavaScript execution.</div><div><br /></div><div>In a nutshell, a sandbox is security mechanism used to run an application in a restricted environment. If an attacker is able to exploit the browser in a way that lets him run arbitrary code on the machine, the sandbox would help prevent this code from causing damage to the system. The sandbox would also help prevent this exploit from modifying and even reading your files or any information on the system.</div><div><br /></div><div>We are very excited to be able to launch Google Chrome with the sandbox enabled on all the platforms we currently support. Even though the sandbox in Google Chrome uses some of the new security features on Windows Vista, it is fully compatible with Windows XP.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">What part of chromium is sandboxed?</span></div><div><br /></div><div>Google Chrome's <a href="http://blog.chromium.org/2008/09/multi-process-architecture.html">multi process architecture</a> allows for a lot of flexibility in the way we do security. The entire HTML rendering and JavaScript execution is isolated to its own class of processes; the renderers. These are the ones that live in the sandbox. We expect to work in the near future with the plug-in vendors to securely sandbox them as well. </div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">How does the sandbox work?</span></div><div><br /></div><div>The sandbox uses the security features of Windows extensively; it does not reinvent any security model.</div><div><br /></div><div>To understand how it works, one needs a basic understanding of the Windows security model. With this model all processes have an <span class="Apple-style-span" style="font-style: italic;">access token</span>. This access token is like an ID card, it contains information about the owner of the process, the list of groups that it belongs to and a list of privileges. Each process has its own token, and the system uses it to deny or grant access to resources. </div><div><br /></div><div>These resources are called <span class="Apple-style-span" style="font-style: italic;">securable objects</span>. They are securable because they are associated with an access control list, or <span class="Apple-style-span" style="font-style: italic;">security descriptor</span>. It contains the security settings of the object. The list of all the users and groups having access to the resource, and what kind of access they have (read, write, execute, etc) can be found there. Files, registry keys, mutexes, pipes, events, semaphores are examples of securable objects.</div><div><br /></div><div>The <span class="Apple-style-span" style="font-style: italic;">access check</span> is the mechanism by which the system determines whether the security descriptor of an object grants the rights requested to an access token. It is performed every time a process tries to acquire a securable object.</div><div><br /></div><div>The process access token is almost entirely customizable. It's possible to remove privileges and disable some groups. This is exactly what the sandbox does. </div><div><br /></div><div>Before launching the renderer process we modify its token to remove all privileges and disable all groups. We then convert the token to a restricted token. A restricted token is like a normal token, but the access checks are performed twice, the first time with the normal information in the token, and the second one using a secondary list of groups. Both access checks have to succeed for the resources to be granted to the process. Google Chrome sets the secondary list of groups to contain only one item, the NULL user. Since this user is never given permissions to any objects, all access checks performed with the access token of the renderer process fail, making this process useless to an attacker.</div><div><br /></div><div>Of course, not all resources on Windows follow this security model. The keyboard, the mouse, the screen and some user objects, like cursors, icons and windows are examples of resources that don't have security descriptors. There is no access check performed when trying to access them. To prevent the renderer from accessing those, the sandbox uses a combination of Job Objects and alternate desktops. A job object is used to apply some restrictions on a group of processes. Some of the restrictions we apply on the renderer process include accessing windows created outside the job, reading or writing to the clipboard, and exiting Windows. We also used an alternate desktop to prevent the renderer from seeing the screen (screen scrapping) or eavesdropping on the keyboard and mouse (key logging). Alternate desktops are commonly used for security. For example, on Windows, the login screen is on another desktop. It ensures that your password can't be stolen by applications running on your normal desktop.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">What are the limitations?</span></div><div><br /></div><div>As we said earlier, the sandbox itself is not a new security model; it relies on Windows to achieve its security. Therefore, it is impossible for us to prevent against a flaw in the OS security model itself. In addition, some legacy file systems, like FAT32, used on certain computers and USB keys don't support security descriptors. Files on these devices can't be protected by the sandbox. Finally, some third party vendors mistakenly configure files, registry keys and other objects in a way that bypasses the access check, giving everyone on the machine full access on them. Unfortunately, it's impossible for the sandbox to protect most of these misconfigured resources.</div><div><br /></div><div>To conclude, it is important to mention that this sandbox was designed to be generic. It is not tied to Google Chrome. It can easily be used by any other projects with a compatible multi-process architecture. You can find more information about the sandbox in the <a href="http://dev.chromium.org/developers/design-documents/sandbox">design doc</a>, and we will post here again about the details of our token manipulation and our policy framework to configure the level of security of the sandbox.</div><div><br /></div><div>We hope you will feel safe browsing the web using Google Chrome, and we are looking forward to your feedback and code contribution!</div><div><br /></div><span class="post-author">Posted by Nicolas Sylvain, Software Engineer</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </noscript> </div> </div> <div class='share'> <span class='twitter-custom social-wrapper' data-href='http://twitter.com/share?text=Chromium Blog:A new approach to browser security: the Google Chrome Sandbox&url=https://blog.chromium.org/2008/10/new-approach-to-browser-security-google.html&via=ChromiumDev'> <img alt='Share on Twitter' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png' width='24'/> </span> <span class='fb-custom social-wrapper' data-href='https://www.facebook.com/sharer.php?u=https://blog.chromium.org/2008/10/new-approach-to-browser-security-google.html'> <img alt='Share on Facebook' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png' width='24'/> </span> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://blog.chromium.org/2008/10/new-approach-to-browser-security-google.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> </div> </div> </div> <div class='post' data-id='8548374418154736288' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2008/10/google-chrome-chromium-and-google.html' itemprop='url' title='Google Chrome, Chromium, and Google'> Google Chrome, Chromium, and Google </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Wednesday, October 1, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <div>A number of people have asked about the relationship between Google Chrome, Chromium, and Google, specifically in regards to what data is sent to Google or other providers. This is meant to provide a complete answer to that question, and as you will see below, almost all such communication can be disabled within the options of the product itself. Before getting too deep into the question though, it is helpful to have a common set of terminology. Chromium is the name we have given to the open source project and the browser source code that we released and maintain at www.chromium.org. One can compile this source code to get a fully working browser. Google takes this source code, and adds on the Google name and logo, an auto-updater system called GoogleUpdate, and RLZ (described later in this post), and calls this Google Chrome. As such, everything which applies to Chromium below also applies to Google Chrome, while there are some things that apply to Google Chrome (such as the auto-updater) that do not apply to Chromium.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">Communications between Chromium (and Google Chrome) and service providers</span></div><div><br /></div><div><span class="Apple-style-span" style="font-style: italic;">Search Suggest</span>: If you type a few letters into the address bar and pause, Google Chrome will send the letters you have typed to your default search provider so it can return a list of suggestions. These suggestions will appear in the drop-down that appears below the address bar.  The letters you have typed are only sent if your search provider provides a suggest service. As an example, suppose your search provider is Google and you're located in the United States. If you type "presid" and pause, you might get suggestions like "Search Google for Presidential Polls", "Search Google for Presidents", as well as a suggested website (a page listing the Presidents of the United States on www.whitehouse.gov). Your provider for search suggestions may log these suggest queries. In the case of Google, we log 2% of these suggest queries, and anonymize these logs within approximately 24 hours as described in an <a href="http://googleblog.blogspot.com/2008/09/update-to-google-suggest.html">earlier blog post</a>.</div><div><br /></div><div>If you choose to accept a search query suggestion, that query will be sent back to your search provider to return a results page. If you choose to accept a suggested website, the accepted suggestion is not sent back to your search provider unless you've opted-in to stats collection. If you have, Google may collect the suggestion you accepted along with the letters you had typed so far in order to improve the suggest service. If you are in a different part of the world, or are using a different search provider, you may get different suggestions. </div><div><br /></div><div>If you do not wish this data to be sent to your search provider, you have a number of options. The first is to use <a href="//www.google.com/support/chrome/bin/answer.py?answer=95464">incognito mode</a>, in which the suggest feature is automatically disabled. You may still get suggestions from your local history stored on your computer, but no suggest queries are sent to your search provider. You can also <a href="//www.google.com/support/chrome/bin/answer.py?answer=95656">turn off search suggestions</a> permanently. Finally, you can <a href="//www.google.com/support/chrome/bin/answer.py?answer=95426">change your search provider</a>. If your new search provider supports suggest functionality (such as Yahoo!), suggest queries will be sent to this new provider. If it does not support suggest functionality then suggest queries will not be sent.</div><div><br /></div><div><span class="Apple-style-span" style="font-style: italic;">Safe Browsing</span>: Safe Browsing is a feature designed to help protect users from phishing and malware. The way Safe Browsing works is that roughly every half hour, an updated list of suspected phishing and malware websites is downloaded from Google and stored locally on your computer. As you browse the web, URLs are checked against these lists that are maintained locally on your computer. If a match against the list is found, a request to Google is sent for more information. This request is formed by taking a 256-bit hash of the URL, and sending the first 32-bits of that hash. To be clear, requests are not sent for each page you visit, and we never send a URL in plain text to Google.  More information on how this feature works is available in the Google Chrome <a href="//www.google.com/support/chrome/bin/answer.py?answer=99020">help center</a>. This feature can also be <a href="//www.google.com/support/chrome/bin/answer.py?answer=95572">disabled</a>, although disabling this feature means that you will not be warned before you visit a suspected phishing website, or a website suspected of downloading and installing malware onto your computer.</div><div><br /></div><div><span class="Apple-style-span" style="font-style: italic;">Suggestions for Navigation Errors</span>: By default, Chromium (and Google Chrome) offer smarter error messages when you encounter unavailable websites. These error messages automatically generate suggestions for webpages with web addresses similar to the one you're trying to access. This feature involves sending the URL that failed to Google, to obtain suggested alternatives. This feature can be <a href="//www.google.com/support/chrome/bin/answer.py?answer=95671">disabled</a> in the options dialog.</div><div><br /></div><div><span class="Apple-style-span" style="font-style: italic;">Which Google Domain</span>: Shortly after startup, Chromium (and Google Chrome) send a request to Google to determine which localized version of Google to use, e.g. whether to direct queries to google.com, google.de, google.co.uk, or another localized version of Google. This is important because sending queries to the right localized Google domain ensures that you get results that are more relevant. For instance, a user searching for "Football" on google.co.uk would get results for European football ("soccer"), while a search on google.com might favor results on American football. Currently (in Google Chrome version 0.2.149), this request is sent regardless of what your default search engine is set to. This was an oversight, and this information was never used to track users.  In Google Chrome 0.3, this request will only be sent if your default search provider is set to Google. This change has already been made in the Chromium source code. </div><div><br /></div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">Communications between Google Chrome (but not Chromium) and service providers</span></div><div><br /></div><div><span class="Apple-style-span" style="font-style: italic;">Usage Statistics and Crash Reports</span>: This option is opt-in, and is disabled by default. Users can elect to send Google their usage statistics and crash reports. This includes statistics on how often Google Chrome features, such as accepting a suggested query or URL in the address bar, are used. Google Chrome doesn't send other personal information, such as name, email address, or Google account information. This option can be <a href="//www.google.com/support/chrome/bin/answer.py?answer=96817">enabled or disabled</a> at any time.</div><div><br /></div><div><span class="Apple-style-span" style="font-style: italic;">GoogleUpdate</span>: When you install Google Chrome, GoogleUpdate is also installed. GoogleUpdate makes sure that your copy of Google Chrome is kept up to date, so that when updates are released your version is automatically updated without any action required on your part. This is especially important to make sure that users are protected by the latest security fixes that Google releases. As part of these update checks, two unique, randomly generated IDs are sent, along with information such as version number, language, operating system, and other install or update-related details. This information helps us accurately count total users, and is not associated with you or your Google Account. More information is <a href="//www.google.com/support/chrome/bin/answer.py?answer=107253">available</a> in the Google Chrome help center. GoogleUpdate cannot be disabled from within Google Chrome. GoogleUpdate is automatically uninstalled on the next update check (typically every few hours) after the last Google product using it is uninstalled. The GoogleUpdate team is working on functionality to allow GoogleUpdate to be uninstalled immediately after the last app using it is uninstalled.</div><div><br /></div><div><span class="Apple-style-span" style="font-style: italic;">RLZ</span>: When you do a Google search from the Google Chrome address bar, an "RLZ parameter" is included in the URL. It is also sent separately on days when Google Chrome has been used or when certain significant events occur such as a successful installation of Google Chrome. RLZ contains some encoded information, such as where you downloaded Google Chrome and where you got it from. This parameter does not uniquely identify you, nor is it used to target advertising. This information is used to understand the effectiveness of different distribution mechanisms, such as downloads directly from Google vs. other distribution channels. More information is <a href="//www.google.com/support/chrome/bin/answer.py?answer=107684">available</a> in the Google Chrome help center. This cannot be disabled so long as your search provider is Google. If your default search provider is not Google, then searches performed using the address bar will go to your default search provider, and will not include this RLZ parameter.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">Updates to Google Chrome's privacy policy</span></div><div> </div><div>In addition to explaining what communications take place between Google Chrome and service providers, we want to let you know that we are updating the <a href="//www.google.com/chrome/intl/en/privacy.html">Google Chrome privacy policy</a> to reflect a change that we have made to the browser to protect user privacy.</div><div><br /></div><div>Since the release of Google Chrome, we have modified the way its browsing history works so that the searchable index of pages you visit does not include sites with "https" web addresses. However, thumbnail-sized screenshots of these pages will be captured for local use, such as on the new tab page. The updated version of the privacy policy reflects this change. As before, your browsing history stays on your own computer for your convenience and is not sent back to Google. And remember: You can delete all or part of your browsing history at any time, or you can conduct your browsing in incognito mode, which does not store browsing history. </div><div><br /></div><div>We hope this new language makes it more clear how Google Chrome works. For more information, check out the <a href="//www.youtube.com/watch?v=pWk8uGdUEkQ">Google Chrome privacy video</a> on our YouTube <a href="//www.youtube.com/googleprivacy">Google Privacy Channel</a>. </div><div><br /></div><span class="post-author">Posted by Ian Fette, Product Manager</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <div>A number of people have asked about the relationship between Google Chrome, Chromium, and Google, specifically in regards to what data is sent to Google or other providers. This is meant to provide a complete answer to that question, and as you will see below, almost all such communication can be disabled within the options of the product itself. Before getting too deep into the question though, it is helpful to have a common set of terminology. Chromium is the name we have given to the open source project and the browser source code that we released and maintain at www.chromium.org. One can compile this source code to get a fully working browser. Google takes this source code, and adds on the Google name and logo, an auto-updater system called GoogleUpdate, and RLZ (described later in this post), and calls this Google Chrome. As such, everything which applies to Chromium below also applies to Google Chrome, while there are some things that apply to Google Chrome (such as the auto-updater) that do not apply to Chromium.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">Communications between Chromium (and Google Chrome) and service providers</span></div><div><br /></div><div><span class="Apple-style-span" style="font-style: italic;">Search Suggest</span>: If you type a few letters into the address bar and pause, Google Chrome will send the letters you have typed to your default search provider so it can return a list of suggestions. These suggestions will appear in the drop-down that appears below the address bar.  The letters you have typed are only sent if your search provider provides a suggest service. As an example, suppose your search provider is Google and you're located in the United States. If you type "presid" and pause, you might get suggestions like "Search Google for Presidential Polls", "Search Google for Presidents", as well as a suggested website (a page listing the Presidents of the United States on www.whitehouse.gov). Your provider for search suggestions may log these suggest queries. In the case of Google, we log 2% of these suggest queries, and anonymize these logs within approximately 24 hours as described in an <a href="http://googleblog.blogspot.com/2008/09/update-to-google-suggest.html">earlier blog post</a>.</div><div><br /></div><div>If you choose to accept a search query suggestion, that query will be sent back to your search provider to return a results page. If you choose to accept a suggested website, the accepted suggestion is not sent back to your search provider unless you've opted-in to stats collection. If you have, Google may collect the suggestion you accepted along with the letters you had typed so far in order to improve the suggest service. If you are in a different part of the world, or are using a different search provider, you may get different suggestions. </div><div><br /></div><div>If you do not wish this data to be sent to your search provider, you have a number of options. The first is to use <a href="//www.google.com/support/chrome/bin/answer.py?answer=95464">incognito mode</a>, in which the suggest feature is automatically disabled. You may still get suggestions from your local history stored on your computer, but no suggest queries are sent to your search provider. You can also <a href="//www.google.com/support/chrome/bin/answer.py?answer=95656">turn off search suggestions</a> permanently. Finally, you can <a href="//www.google.com/support/chrome/bin/answer.py?answer=95426">change your search provider</a>. If your new search provider supports suggest functionality (such as Yahoo!), suggest queries will be sent to this new provider. If it does not support suggest functionality then suggest queries will not be sent.</div><div><br /></div><div><span class="Apple-style-span" style="font-style: italic;">Safe Browsing</span>: Safe Browsing is a feature designed to help protect users from phishing and malware. The way Safe Browsing works is that roughly every half hour, an updated list of suspected phishing and malware websites is downloaded from Google and stored locally on your computer. As you browse the web, URLs are checked against these lists that are maintained locally on your computer. If a match against the list is found, a request to Google is sent for more information. This request is formed by taking a 256-bit hash of the URL, and sending the first 32-bits of that hash. To be clear, requests are not sent for each page you visit, and we never send a URL in plain text to Google.  More information on how this feature works is available in the Google Chrome <a href="//www.google.com/support/chrome/bin/answer.py?answer=99020">help center</a>. This feature can also be <a href="//www.google.com/support/chrome/bin/answer.py?answer=95572">disabled</a>, although disabling this feature means that you will not be warned before you visit a suspected phishing website, or a website suspected of downloading and installing malware onto your computer.</div><div><br /></div><div><span class="Apple-style-span" style="font-style: italic;">Suggestions for Navigation Errors</span>: By default, Chromium (and Google Chrome) offer smarter error messages when you encounter unavailable websites. These error messages automatically generate suggestions for webpages with web addresses similar to the one you're trying to access. This feature involves sending the URL that failed to Google, to obtain suggested alternatives. This feature can be <a href="//www.google.com/support/chrome/bin/answer.py?answer=95671">disabled</a> in the options dialog.</div><div><br /></div><div><span class="Apple-style-span" style="font-style: italic;">Which Google Domain</span>: Shortly after startup, Chromium (and Google Chrome) send a request to Google to determine which localized version of Google to use, e.g. whether to direct queries to google.com, google.de, google.co.uk, or another localized version of Google. This is important because sending queries to the right localized Google domain ensures that you get results that are more relevant. For instance, a user searching for "Football" on google.co.uk would get results for European football ("soccer"), while a search on google.com might favor results on American football. Currently (in Google Chrome version 0.2.149), this request is sent regardless of what your default search engine is set to. This was an oversight, and this information was never used to track users.  In Google Chrome 0.3, this request will only be sent if your default search provider is set to Google. This change has already been made in the Chromium source code. </div><div><br /></div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">Communications between Google Chrome (but not Chromium) and service providers</span></div><div><br /></div><div><span class="Apple-style-span" style="font-style: italic;">Usage Statistics and Crash Reports</span>: This option is opt-in, and is disabled by default. Users can elect to send Google their usage statistics and crash reports. This includes statistics on how often Google Chrome features, such as accepting a suggested query or URL in the address bar, are used. Google Chrome doesn't send other personal information, such as name, email address, or Google account information. This option can be <a href="//www.google.com/support/chrome/bin/answer.py?answer=96817">enabled or disabled</a> at any time.</div><div><br /></div><div><span class="Apple-style-span" style="font-style: italic;">GoogleUpdate</span>: When you install Google Chrome, GoogleUpdate is also installed. GoogleUpdate makes sure that your copy of Google Chrome is kept up to date, so that when updates are released your version is automatically updated without any action required on your part. This is especially important to make sure that users are protected by the latest security fixes that Google releases. As part of these update checks, two unique, randomly generated IDs are sent, along with information such as version number, language, operating system, and other install or update-related details. This information helps us accurately count total users, and is not associated with you or your Google Account. More information is <a href="//www.google.com/support/chrome/bin/answer.py?answer=107253">available</a> in the Google Chrome help center. GoogleUpdate cannot be disabled from within Google Chrome. GoogleUpdate is automatically uninstalled on the next update check (typically every few hours) after the last Google product using it is uninstalled. The GoogleUpdate team is working on functionality to allow GoogleUpdate to be uninstalled immediately after the last app using it is uninstalled.</div><div><br /></div><div><span class="Apple-style-span" style="font-style: italic;">RLZ</span>: When you do a Google search from the Google Chrome address bar, an "RLZ parameter" is included in the URL. It is also sent separately on days when Google Chrome has been used or when certain significant events occur such as a successful installation of Google Chrome. RLZ contains some encoded information, such as where you downloaded Google Chrome and where you got it from. This parameter does not uniquely identify you, nor is it used to target advertising. This information is used to understand the effectiveness of different distribution mechanisms, such as downloads directly from Google vs. other distribution channels. More information is <a href="//www.google.com/support/chrome/bin/answer.py?answer=107684">available</a> in the Google Chrome help center. This cannot be disabled so long as your search provider is Google. If your default search provider is not Google, then searches performed using the address bar will go to your default search provider, and will not include this RLZ parameter.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">Updates to Google Chrome's privacy policy</span></div><div> </div><div>In addition to explaining what communications take place between Google Chrome and service providers, we want to let you know that we are updating the <a href="//www.google.com/chrome/intl/en/privacy.html">Google Chrome privacy policy</a> to reflect a change that we have made to the browser to protect user privacy.</div><div><br /></div><div>Since the release of Google Chrome, we have modified the way its browsing history works so that the searchable index of pages you visit does not include sites with "https" web addresses. However, thumbnail-sized screenshots of these pages will be captured for local use, such as on the new tab page. The updated version of the privacy policy reflects this change. As before, your browsing history stays on your own computer for your convenience and is not sent back to Google. And remember: You can delete all or part of your browsing history at any time, or you can conduct your browsing in incognito mode, which does not store browsing history. </div><div><br /></div><div>We hope this new language makes it more clear how Google Chrome works. For more information, check out the <a href="//www.youtube.com/watch?v=pWk8uGdUEkQ">Google Chrome privacy video</a> on our YouTube <a href="//www.youtube.com/googleprivacy">Google Privacy Channel</a>. </div><div><br /></div><span class="post-author">Posted by Ian Fette, Product Manager</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </noscript> </div> </div> <div class='share'> <span class='twitter-custom social-wrapper' data-href='http://twitter.com/share?text=Chromium Blog:Google Chrome, Chromium, and Google&url=https://blog.chromium.org/2008/10/google-chrome-chromium-and-google.html&via=ChromiumDev'> <img alt='Share on Twitter' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png' width='24'/> </span> <span class='fb-custom social-wrapper' data-href='https://www.facebook.com/sharer.php?u=https://blog.chromium.org/2008/10/google-chrome-chromium-and-google.html'> <img alt='Share on Facebook' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png' width='24'/> </span> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://blog.chromium.org/2008/10/google-chrome-chromium-and-google.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> </div> </div> </div> <div class='post' data-id='5811482738591755633' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2008/09/google-chrome-memory-usage-good-and-bad.html' itemprop='url' title='Google Chrome Memory Usage - Good and Bad'> Google Chrome Memory Usage - Good and Bad </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Friday, September 19, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <div> A lot of smart people are doing some serious tire kicking on Google Chrome. Now with several days of testing under their belts, we're seeing many observations about Google Chrome's memory usage. I've just posted a <a href="http://dev.chromium.org/memory-usage-backgrounder">techie document</a> about memory over on the developer website as an initial brain-dump of our current thinking about memory usage within Google Chrome. This article is a quick summary.</div> <div> <br /></div> <div> <span class="Apple-style-span" style="font-weight: bold;">Measuring memory</span></div> <div> <span class="Apple-style-span" style="font-weight: bold;"><br /></span></div> <div> If you're measuring memory in a multi-process application like Google Chrome, don't forget to take into account shared memory. If you add the size of each process via the Windows XP task manager, you'll be double counting the shared memory for each process. If there are a large number of processes, double-counting can account for 30-40% extra memory size.</div> <div> <br /></div> <div> To make it easy to summarize multi-process memory usage, Google Chrome provides the "about:memory" page which includes a detailed breakdown of Google Chrome's memory usage and also provides basic comparisons to other browsers that are running.</div> <div> <br /></div> <div> <span class="Apple-style-span" style="font-weight: bold;">Multi-process Model Disadvantages</span></div> <div> <span class="Apple-style-span" style="font-weight: bold;"><br /></span></div> <div> While the multi-process model provides clear robustness and performance benefits, it can also be a setback in terms of using the absolute smallest amount of memory. Since each tab is its own "sandboxed" process, tabs cannot share information easily. Any data structures needed for general rendering of web pages must be replicated to each tab. We've done our best to minimize this, but we have a lot more work to do.</div> <div> <br /></div> <div> <span class="Apple-style-span" style="font-style: italic;">Example</span>: Try opening the browser with 10 different sites in 10 tabs. You will probably notice that Google Chrome uses significantly more memory than single-process browsers do for this case.</div> <div> <br /></div> <div> Keep in mind that we believe this is a good trade-off. For example; each tab has it's own JavaScript engine. An attack compromising one tab's Javascript engine is much less likely to be able to gain access to another tab (which may contain banking information) due to process separation. Operating systems vendors learned long ago that there are many benefits to not having all applications load into a single process space, despite the fact that multiple processes do incur overhead.</div> <div> <br /></div> <div> <span class="Apple-style-span" style="font-weight: bold;">Multi-process advantages</span></div> <div> <span class="Apple-style-span" style="font-weight: bold;"><br /></span></div> <div> Despite the setback, the multi-process model has advantages too. The primary advantage is the ability to partition memory for particular pages. So, when you close a page (tab), that partition of memory can be completely cleaned up. This is much more difficult to do in a single-process browser.</div> <div> <br /></div> <div> To demonstrate, lets expand on the example above. Now that you have 10 open tabs in a single process browser and Google Chrome, try closing 9 of them, and check the memory usage. Hopefully, this will demonstrate that Google Chrome is actually able to reclaim more memory than the single process browser generally can. We hope this is indicative of general user behavior, where many sites are visited on a daily basis; but when the user leaves a site, we want to cleanup everything.</div> <div> <br /></div> <div> You can find even more details in the <a href="http://www.chromium.org/developers/memory-usage-backgrounder">design doc</a> in our Chromium <a href="http://dev.chromium.org/">developer website</a>.</div> <br /> <span class="post-author">Posted by Mike Belshe, Software Engineer</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <div> A lot of smart people are doing some serious tire kicking on Google Chrome. Now with several days of testing under their belts, we're seeing many observations about Google Chrome's memory usage. I've just posted a <a href="http://dev.chromium.org/memory-usage-backgrounder">techie document</a> about memory over on the developer website as an initial brain-dump of our current thinking about memory usage within Google Chrome. This article is a quick summary.</div> <div> <br /></div> <div> <span class="Apple-style-span" style="font-weight: bold;">Measuring memory</span></div> <div> <span class="Apple-style-span" style="font-weight: bold;"><br /></span></div> <div> If you're measuring memory in a multi-process application like Google Chrome, don't forget to take into account shared memory. If you add the size of each process via the Windows XP task manager, you'll be double counting the shared memory for each process. If there are a large number of processes, double-counting can account for 30-40% extra memory size.</div> <div> <br /></div> <div> To make it easy to summarize multi-process memory usage, Google Chrome provides the "about:memory" page which includes a detailed breakdown of Google Chrome's memory usage and also provides basic comparisons to other browsers that are running.</div> <div> <br /></div> <div> <span class="Apple-style-span" style="font-weight: bold;">Multi-process Model Disadvantages</span></div> <div> <span class="Apple-style-span" style="font-weight: bold;"><br /></span></div> <div> While the multi-process model provides clear robustness and performance benefits, it can also be a setback in terms of using the absolute smallest amount of memory. Since each tab is its own "sandboxed" process, tabs cannot share information easily. Any data structures needed for general rendering of web pages must be replicated to each tab. We've done our best to minimize this, but we have a lot more work to do.</div> <div> <br /></div> <div> <span class="Apple-style-span" style="font-style: italic;">Example</span>: Try opening the browser with 10 different sites in 10 tabs. You will probably notice that Google Chrome uses significantly more memory than single-process browsers do for this case.</div> <div> <br /></div> <div> Keep in mind that we believe this is a good trade-off. For example; each tab has it's own JavaScript engine. An attack compromising one tab's Javascript engine is much less likely to be able to gain access to another tab (which may contain banking information) due to process separation. Operating systems vendors learned long ago that there are many benefits to not having all applications load into a single process space, despite the fact that multiple processes do incur overhead.</div> <div> <br /></div> <div> <span class="Apple-style-span" style="font-weight: bold;">Multi-process advantages</span></div> <div> <span class="Apple-style-span" style="font-weight: bold;"><br /></span></div> <div> Despite the setback, the multi-process model has advantages too. The primary advantage is the ability to partition memory for particular pages. So, when you close a page (tab), that partition of memory can be completely cleaned up. This is much more difficult to do in a single-process browser.</div> <div> <br /></div> <div> To demonstrate, lets expand on the example above. Now that you have 10 open tabs in a single process browser and Google Chrome, try closing 9 of them, and check the memory usage. Hopefully, this will demonstrate that Google Chrome is actually able to reclaim more memory than the single process browser generally can. We hope this is indicative of general user behavior, where many sites are visited on a daily basis; but when the user leaves a site, we want to cleanup everything.</div> <div> <br /></div> <div> You can find even more details in the <a href="http://www.chromium.org/developers/memory-usage-backgrounder">design doc</a> in our Chromium <a href="http://dev.chromium.org/">developer website</a>.</div> <br /> <span class="post-author">Posted by Mike Belshe, Software Engineer</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </noscript> </div> </div> <div class='share'> <span class='twitter-custom social-wrapper' data-href='http://twitter.com/share?text=Chromium Blog:Google Chrome Memory Usage - Good and Bad&url=https://blog.chromium.org/2008/09/google-chrome-memory-usage-good-and-bad.html&via=ChromiumDev'> <img alt='Share on Twitter' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png' width='24'/> </span> <span class='fb-custom social-wrapper' data-href='https://www.facebook.com/sharer.php?u=https://blog.chromium.org/2008/09/google-chrome-memory-usage-good-and-bad.html'> <img alt='Share on Facebook' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png' width='24'/> </span> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://blog.chromium.org/2008/09/google-chrome-memory-usage-good-and-bad.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> </div> </div> </div> <div class='post' data-id='2487642070899356588' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2008/09/dns-prefetching-or-pre-resolving.html' itemprop='url' title='DNS Prefetching (or Pre-Resolving)'> DNS Prefetching (or Pre-Resolving) </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Wednesday, September 17, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <div>A major goal of Google Chrome was to improve user enjoyment and value in web surfing. Critical to that is increasing the responsiveness of the browser to user input, or reducing user perceived latency. Measurements in the browser have shown that a significant amount of time is traditionally spent waiting for DNS to resolve domain names. To speed up browsing, Google Chrome resolves domain names before the user navigates, typically while the user is viewing a web page. This is done using your computer's normal DNS resolution mechanism; no connection to Google is used. As a result, user navigation time in Google Chrome when first visiting a domain is on average about 250ms faster than traditional browsing, and the occasional but painful 1-second-plus delays are almost never experienced.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">How it works, and how much it helps.</span></div><div><br /></div><div>First off, DNS Resolution is the translation of a domain name, such as www.google.com, into an IP address, such as 74.125.19.147. A user can't go anywhere on the internet until after the target domain is resolved via DNS.</div><div><br /></div><div>The histograms at the end of this post show actual resolution times encountered when computers needed to contact their network for DNS resolutions. The data was gathered during our pre-release testing by Google employees who opted-in to contributing their results. As can be seen in that data, the average latency was generally around 250ms, and many resolutions took over 1 second, some even several seconds.</div><div><br /></div><div>DNS prefetching just resolves domain names before a user tries to navigate, so that there will be no effective user delay due to DNS resolution. The most obvious example where prefetching can help is when a user is looking at a page with many links to various unexplored domains, such as a search results page. Google Chrome automatically scans the content of each rendered page looking for links, extracting the domain name from each link, and resolving each domain to an IP address. All this work is done in parallel with the user's reading of the page, hardly using any CPU power. When a user clicks on any of these pre-resolved names to visit a new domain, they will save an average of over 250ms in their navigation.  </div><div><br /></div><div>If you've been running Google Chrome for a while, be sure to try typing "about:dns" into the address bar to see what savings you've accrued! Humorously, this prefetching feature often goes unnoticed, as users simply avoid the pain of waiting, and tend to think the network is just fast and smooth. To look at it another way, DNS prefetching removes the variance from surfing latency that is induced by DNS resolutions. (Note: If about:dns doesn't show any savings, then you probably are using a proxy, which is resolving DNS on the behalf of your browser.)</div><div><br /></div><div>There are several other benefits that Google Chrome derives from DNS prefetching. During startup, it pre-resolves domain names, such as the home pages, very early in the startup process. This tends to save about 200-500 ms during application startups. Google Chrome also pre-resolves the host names in URLs suggested by the omnibox while the user is typing, but before they press enter. This feature works independently of the broader omnibox logic, and doesn't utilize any connection to Google. As a result, Google Chrome will generally navigate to a typed URL faster, or reach a user's search provider faster. Depending on the popularity of the target domain, this can save 100-250ms on average, and much more in the worst case.</div><div><br /></div><div>If you are running Google Chrome, try typing "about:histograms/DNS.PrefetchFoundName" into the address bar to see details of the resolution times currently being encountered on your machine.</div><div><br /></div><div>The bottom line to all this DNS prefetching is that Google Chrome works overtime, anticipating a user's needs, and making sure they have a very smooth surfing experience. Google Chrome doesn't just render and run Java Script at a remarkable speed, it gets users to their destinations quickly, and generally sidesteps the pitfalls surrounding DNS resolution time.</div><div><br /></div><div>Of course, the best way to see this DNS prefetching feature work, is to just surf.  </div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">Sample of DNS Resolutions Times requiring Network Activity (i.e., over 15ms resolution)</span></div><div><br /></div><div>The following is a recent histogram of aggregated DNS resolutions times observed during tests of Google Chrome by Googlers, prior to the product's public release. The samples listed are only those that required network access (i.e., took more than 15 ms). The left column lists the lower range of each bucket.  For example, the first bucket lists samples between 14 and 18ms inclusive. The next three columns show the number of samples in that range, the fraction of samples in the range, and the cumulative fraction of samples at or below that range. For example, in the first bucket, there were 31761 samples in this bucket range, or about 5.10% of all the 6,228,600 samples shown. Looking at the cumulative percentage column (far right), we can see that the median resolution took around 90ms (actually, 52.71% took less than 118ms, but 43.63% took less than 87ms). Reading from the top of the chart, the average DNS resolution time was 271ms, and the standard deviation was 1.130 seconds. The "long tail" may have included users that lost network connectivity, and eventually reconnected, producing extraordinarily long resolution times.</div><div><br /></div><div><br /></div><div>Count: 6,228,600; Sum of times: 1,689,207,135; Mean: 271 ± 1130.67</div><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhexvlDry4dzIGdazF6k6cgsZy6qjvdvPjPu6auwhhfNyTe6WXG9BjW-bGHv0Tei6fWXHKXLVZvb09aBmpp03XCJpAj4aOWyIZiWYyhrOmBrU16PMErwlqqBZz61NczyuBHzRBOPlJUbVMX/s1600-h/histogram.PNG"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5247044084893705170" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhexvlDry4dzIGdazF6k6cgsZy6qjvdvPjPu6auwhhfNyTe6WXG9BjW-bGHv0Tei6fWXHKXLVZvb09aBmpp03XCJpAj4aOWyIZiWYyhrOmBrU16PMErwlqqBZz61NczyuBHzRBOPlJUbVMX/s400/histogram.PNG" style="cursor:pointer; cursor:hand;" /></a><br /><span class="post-author"><div><br /></div>Posted by Jim Roskind, Software Engineer</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <div>A major goal of Google Chrome was to improve user enjoyment and value in web surfing. Critical to that is increasing the responsiveness of the browser to user input, or reducing user perceived latency. Measurements in the browser have shown that a significant amount of time is traditionally spent waiting for DNS to resolve domain names. To speed up browsing, Google Chrome resolves domain names before the user navigates, typically while the user is viewing a web page. This is done using your computer's normal DNS resolution mechanism; no connection to Google is used. As a result, user navigation time in Google Chrome when first visiting a domain is on average about 250ms faster than traditional browsing, and the occasional but painful 1-second-plus delays are almost never experienced.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">How it works, and how much it helps.</span></div><div><br /></div><div>First off, DNS Resolution is the translation of a domain name, such as www.google.com, into an IP address, such as 74.125.19.147. A user can't go anywhere on the internet until after the target domain is resolved via DNS.</div><div><br /></div><div>The histograms at the end of this post show actual resolution times encountered when computers needed to contact their network for DNS resolutions. The data was gathered during our pre-release testing by Google employees who opted-in to contributing their results. As can be seen in that data, the average latency was generally around 250ms, and many resolutions took over 1 second, some even several seconds.</div><div><br /></div><div>DNS prefetching just resolves domain names before a user tries to navigate, so that there will be no effective user delay due to DNS resolution. The most obvious example where prefetching can help is when a user is looking at a page with many links to various unexplored domains, such as a search results page. Google Chrome automatically scans the content of each rendered page looking for links, extracting the domain name from each link, and resolving each domain to an IP address. All this work is done in parallel with the user's reading of the page, hardly using any CPU power. When a user clicks on any of these pre-resolved names to visit a new domain, they will save an average of over 250ms in their navigation.  </div><div><br /></div><div>If you've been running Google Chrome for a while, be sure to try typing "about:dns" into the address bar to see what savings you've accrued! Humorously, this prefetching feature often goes unnoticed, as users simply avoid the pain of waiting, and tend to think the network is just fast and smooth. To look at it another way, DNS prefetching removes the variance from surfing latency that is induced by DNS resolutions. (Note: If about:dns doesn't show any savings, then you probably are using a proxy, which is resolving DNS on the behalf of your browser.)</div><div><br /></div><div>There are several other benefits that Google Chrome derives from DNS prefetching. During startup, it pre-resolves domain names, such as the home pages, very early in the startup process. This tends to save about 200-500 ms during application startups. Google Chrome also pre-resolves the host names in URLs suggested by the omnibox while the user is typing, but before they press enter. This feature works independently of the broader omnibox logic, and doesn't utilize any connection to Google. As a result, Google Chrome will generally navigate to a typed URL faster, or reach a user's search provider faster. Depending on the popularity of the target domain, this can save 100-250ms on average, and much more in the worst case.</div><div><br /></div><div>If you are running Google Chrome, try typing "about:histograms/DNS.PrefetchFoundName" into the address bar to see details of the resolution times currently being encountered on your machine.</div><div><br /></div><div>The bottom line to all this DNS prefetching is that Google Chrome works overtime, anticipating a user's needs, and making sure they have a very smooth surfing experience. Google Chrome doesn't just render and run Java Script at a remarkable speed, it gets users to their destinations quickly, and generally sidesteps the pitfalls surrounding DNS resolution time.</div><div><br /></div><div>Of course, the best way to see this DNS prefetching feature work, is to just surf.  </div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">Sample of DNS Resolutions Times requiring Network Activity (i.e., over 15ms resolution)</span></div><div><br /></div><div>The following is a recent histogram of aggregated DNS resolutions times observed during tests of Google Chrome by Googlers, prior to the product's public release. The samples listed are only those that required network access (i.e., took more than 15 ms). The left column lists the lower range of each bucket.  For example, the first bucket lists samples between 14 and 18ms inclusive. The next three columns show the number of samples in that range, the fraction of samples in the range, and the cumulative fraction of samples at or below that range. For example, in the first bucket, there were 31761 samples in this bucket range, or about 5.10% of all the 6,228,600 samples shown. Looking at the cumulative percentage column (far right), we can see that the median resolution took around 90ms (actually, 52.71% took less than 118ms, but 43.63% took less than 87ms). Reading from the top of the chart, the average DNS resolution time was 271ms, and the standard deviation was 1.130 seconds. The "long tail" may have included users that lost network connectivity, and eventually reconnected, producing extraordinarily long resolution times.</div><div><br /></div><div><br /></div><div>Count: 6,228,600; Sum of times: 1,689,207,135; Mean: 271 ± 1130.67</div><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhexvlDry4dzIGdazF6k6cgsZy6qjvdvPjPu6auwhhfNyTe6WXG9BjW-bGHv0Tei6fWXHKXLVZvb09aBmpp03XCJpAj4aOWyIZiWYyhrOmBrU16PMErwlqqBZz61NczyuBHzRBOPlJUbVMX/s1600-h/histogram.PNG"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5247044084893705170" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhexvlDry4dzIGdazF6k6cgsZy6qjvdvPjPu6auwhhfNyTe6WXG9BjW-bGHv0Tei6fWXHKXLVZvb09aBmpp03XCJpAj4aOWyIZiWYyhrOmBrU16PMErwlqqBZz61NczyuBHzRBOPlJUbVMX/s400/histogram.PNG" style="cursor:pointer; cursor:hand;" /></a><br /><span class="post-author"><div><br /></div>Posted by Jim Roskind, Software Engineer</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </noscript> </div> </div> <div class='share'> <span class='twitter-custom social-wrapper' data-href='http://twitter.com/share?text=Chromium Blog:DNS Prefetching (or Pre-Resolving)&url=https://blog.chromium.org/2008/09/dns-prefetching-or-pre-resolving.html&via=ChromiumDev'> <img alt='Share on Twitter' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png' width='24'/> </span> <span class='fb-custom social-wrapper' data-href='https://www.facebook.com/sharer.php?u=https://blog.chromium.org/2008/09/dns-prefetching-or-pre-resolving.html'> <img alt='Share on Facebook' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png' width='24'/> </span> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://blog.chromium.org/2008/09/dns-prefetching-or-pre-resolving.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> </div> </div> </div> <div class='post' data-id='3532286548361325434' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2008/09/multi-process-architecture.html' itemprop='url' title='Multi-process Architecture'> Multi-process Architecture </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Thursday, September 11, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <div>Unlike most current web browsers, Google Chrome uses many operating system processes to keep web sites separate from each other and from the rest of your computer.  In this blog post, I'll explain why using a multi-process architecture can be a big win for browsers on today's web.  I'll also talk about which parts of the browser belong in each process and in which situations Google Chrome creates new processes.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">1. Why use multiple processes in a browser?</span></div><div><br /></div><div>In the days when most current browsers were designed, web pages were simple and had little or no active code in them.  It made sense for the browser to render all the pages you visited in the same process, to keep resource usage low.</div><div><br /></div><div>Today, however, we've seen a major shift towards active web content, ranging from pages with lots of JavaScript and Flash to full-blown "web apps" like Gmail.  Large parts of these apps run inside the browser, just like normal applications run on an operating system.  Just like an operating system, the browser must keep these apps separate from each other.</div><div><br /></div><div>On top of this, the parts of the browser that render HTML, JavaScript, and CSS have become extraordinarily complex over time.  These rendering engines frequently have bugs as they continue to evolve, and some of these bugs may cause the rendering engine to occasionally crash.  Also, rendering engines routinely face untrusted and even malicious code from the web, which may try to exploit these bugs to install malware on your computer.</div><div><br /></div><div>In this world, browsers that put everything in one process face real challenges for robustness, responsiveness, and security.  If one web app causes a crash in the rendering engine, it will take the rest of the browser with it, including any other web apps that are open.  Web apps often have to compete with each other for CPU time on a single thread, sometimes causing the entire browser to become unresponsive.  Security is also a concern, because a web page that exploits a vulnerability in the rendering engine can often take over your entire computer.</div><div><br /></div><div>It doesn't have to be this way, though.  Web apps are designed to be run independently of each other in your browser, and they could be run in parallel.  They don't need much access to your disk or devices, either.  The security policy used throughout the web ensures this, so that you can visit most web pages without worrying about your data or your computer's safety.  This means that it's possible to more completely isolate web apps from each other in the browser without breaking them.  The same is true of browser plug-ins like Flash, which are loosely coupled with the browser and can be separated from it without much trouble.</div><div><br /></div><div>Google Chrome takes advantage of these properties and puts web apps and plug-ins in separate processes from the browser itself.  This means that a rendering engine crash in one web app won't affect the browser or other web apps.  It means the OS can run web apps in parallel to increase their responsiveness, and it means the browser itself won't lock up if a particular web app or plug-in stops responding.  It also means we can run the rendering engine processes in a restrictive sandbox that helps limit the damage if an exploit does occur.</div><div><br /></div><div>Interestingly, using multiple processes means Google Chrome can have its own Task Manager (shown below), which you can get to by right clicking on the browser's title bar.  This Task Manager lets you track resource usage for each web app and plug-in, rather than for the entire browser.  It also lets you kill any web apps or plug-ins that have stopped responding, without having to restart the entire browser.</div><div><br /></div><div><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj48MppTSKa7HB85URmaKLXou5Q4JBtW0gbpHQREiGqq2-m-igl0bik-LQW5sxhdtYq15ZxSJbfzfdJik7hD62uiuaoamEh0HVd5VvgLZljmgoZh1J8xO0_nWQO1wPd3lh-kJqNXOfa2Roc/s400/google_chrome_task_manager.png" style="margin:0" /></div><br /><div>For all of these reasons, Google Chrome's multi-process architecture can help it be more robust, responsive, and secure than single process browsers.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">2. What goes in each process?</span></div><div><br /></div><div>Google Chrome creates three different types of processes: browser, renderers, and plug-ins.</div><div><br /></div><div><span class="Apple-style-span" style="font-style: italic;">Browser</span>.  There's only one browser process, which manages the tabs, windows, and "chrome" of the browser.  This process also handles all interactions with the disk, network, user input, and display, but it makes no attempt to parse or render any content from the web.</div><div><br /></div><div><span class="Apple-style-span" style="font-style: italic;">Renderers</span>.  The browser process creates many renderer processes, each responsible for rendering web pages.  The renderer processes contain all the complex logic for handling HTML, JavaScript, CSS, images, and so on.  We achieve this using the open source WebKit rendering engine, which is also used by Apple's Safari web browser.  Each renderer process is run in a sandbox, which means it has almost no direct access to your disk, network, or display.  All interactions with web apps, including user input events and screen painting, must go through the browser process.  This lets the browser process monitor the renderers for suspicious activity, killing them if it suspects an exploit has occurred.</div><div><br /></div><div><span class="Apple-style-span" style="font-style: italic;">Plug-ins</span>.  The browser process also creates one process for each type of plug-in that is in use, such as Flash, Quicktime, or Adobe Reader.  These processes just contain the plug-ins themselves, along with some glue code to let them interact with the browser and renderers.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">3. When should the browser create processes?</span></div><div><br /></div><div>Once Google Chrome has created its browser process, it will generally create one renderer process for each instance of a web site you visit.  This approach aims to keep pages from different web sites isolated from each other.</div><div><br /></div><div>You can think of this as using a different process for each tab in the browser, but allowing two tabs to share a process if they are related to each other and are showing the same site.  For example, if one tab opens another tab using JavaScript, or if you open a link to the same site in a new tab, the tabs will share a renderer process.  This lets the pages in these tabs communicate via JavaScript and share cached objects.  Conversely, if you type the URL of a different site into the location bar of a tab, we will swap in a new renderer process for the tab.</div><div><br /></div><div>Compatibility with existing web pages is important for us.  For this reason, we define a web site as a registered domain name, like google.com or bbc.co.uk.  This means we'll consider sub-domains like mail.google.com and maps.google.com as part of the same site.  This is necessary because there are cases where tabs from different sub-domains may try to communicate with each other via JavaScript, so we want to keep them in the same renderer process.</div><div><br /></div><div>There are a few caveats to this basic approach, however.  Your computer would start to slow down if we created too many processes, so we place a limit on the number of renderer processes that we create (20 in most cases).  Once we hit this limit, we'll start re-using the existing renderer processes for new tabs.  Thus, it's possible that the same renderer process could be used for more than one web site.  We also don't yet put cross-site frames in their own processes, and we don't yet swap a tab's renderer process for all types of cross-site navigations.  So far, we only swap a tab's process for navigations via the browser's "chrome," like the location bar or bookmarks.  Despite these caveats, Google Chrome will generally keep instances of different web sites isolated from each other in common usage.</div><div><br /></div><div>For each type of plug-in, Google Chrome will create a plug-in process when you first visit a page that uses it.  A short time after you close all pages using a particular plug-in, we will destroy its process.</div><div><br /></div><div>We'll post future blog entries as we refine our policies for creating and swapping among renderer processes.  In the mean time, we hope you see some of the benefits of a multi-process architecture when using Google Chrome.</div><div><br /></div><span class="post-author">Posted by Charlie Reis</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <div>Unlike most current web browsers, Google Chrome uses many operating system processes to keep web sites separate from each other and from the rest of your computer.  In this blog post, I'll explain why using a multi-process architecture can be a big win for browsers on today's web.  I'll also talk about which parts of the browser belong in each process and in which situations Google Chrome creates new processes.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">1. Why use multiple processes in a browser?</span></div><div><br /></div><div>In the days when most current browsers were designed, web pages were simple and had little or no active code in them.  It made sense for the browser to render all the pages you visited in the same process, to keep resource usage low.</div><div><br /></div><div>Today, however, we've seen a major shift towards active web content, ranging from pages with lots of JavaScript and Flash to full-blown "web apps" like Gmail.  Large parts of these apps run inside the browser, just like normal applications run on an operating system.  Just like an operating system, the browser must keep these apps separate from each other.</div><div><br /></div><div>On top of this, the parts of the browser that render HTML, JavaScript, and CSS have become extraordinarily complex over time.  These rendering engines frequently have bugs as they continue to evolve, and some of these bugs may cause the rendering engine to occasionally crash.  Also, rendering engines routinely face untrusted and even malicious code from the web, which may try to exploit these bugs to install malware on your computer.</div><div><br /></div><div>In this world, browsers that put everything in one process face real challenges for robustness, responsiveness, and security.  If one web app causes a crash in the rendering engine, it will take the rest of the browser with it, including any other web apps that are open.  Web apps often have to compete with each other for CPU time on a single thread, sometimes causing the entire browser to become unresponsive.  Security is also a concern, because a web page that exploits a vulnerability in the rendering engine can often take over your entire computer.</div><div><br /></div><div>It doesn't have to be this way, though.  Web apps are designed to be run independently of each other in your browser, and they could be run in parallel.  They don't need much access to your disk or devices, either.  The security policy used throughout the web ensures this, so that you can visit most web pages without worrying about your data or your computer's safety.  This means that it's possible to more completely isolate web apps from each other in the browser without breaking them.  The same is true of browser plug-ins like Flash, which are loosely coupled with the browser and can be separated from it without much trouble.</div><div><br /></div><div>Google Chrome takes advantage of these properties and puts web apps and plug-ins in separate processes from the browser itself.  This means that a rendering engine crash in one web app won't affect the browser or other web apps.  It means the OS can run web apps in parallel to increase their responsiveness, and it means the browser itself won't lock up if a particular web app or plug-in stops responding.  It also means we can run the rendering engine processes in a restrictive sandbox that helps limit the damage if an exploit does occur.</div><div><br /></div><div>Interestingly, using multiple processes means Google Chrome can have its own Task Manager (shown below), which you can get to by right clicking on the browser's title bar.  This Task Manager lets you track resource usage for each web app and plug-in, rather than for the entire browser.  It also lets you kill any web apps or plug-ins that have stopped responding, without having to restart the entire browser.</div><div><br /></div><div><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj48MppTSKa7HB85URmaKLXou5Q4JBtW0gbpHQREiGqq2-m-igl0bik-LQW5sxhdtYq15ZxSJbfzfdJik7hD62uiuaoamEh0HVd5VvgLZljmgoZh1J8xO0_nWQO1wPd3lh-kJqNXOfa2Roc/s400/google_chrome_task_manager.png" style="margin:0" /></div><br /><div>For all of these reasons, Google Chrome's multi-process architecture can help it be more robust, responsive, and secure than single process browsers.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">2. What goes in each process?</span></div><div><br /></div><div>Google Chrome creates three different types of processes: browser, renderers, and plug-ins.</div><div><br /></div><div><span class="Apple-style-span" style="font-style: italic;">Browser</span>.  There's only one browser process, which manages the tabs, windows, and "chrome" of the browser.  This process also handles all interactions with the disk, network, user input, and display, but it makes no attempt to parse or render any content from the web.</div><div><br /></div><div><span class="Apple-style-span" style="font-style: italic;">Renderers</span>.  The browser process creates many renderer processes, each responsible for rendering web pages.  The renderer processes contain all the complex logic for handling HTML, JavaScript, CSS, images, and so on.  We achieve this using the open source WebKit rendering engine, which is also used by Apple's Safari web browser.  Each renderer process is run in a sandbox, which means it has almost no direct access to your disk, network, or display.  All interactions with web apps, including user input events and screen painting, must go through the browser process.  This lets the browser process monitor the renderers for suspicious activity, killing them if it suspects an exploit has occurred.</div><div><br /></div><div><span class="Apple-style-span" style="font-style: italic;">Plug-ins</span>.  The browser process also creates one process for each type of plug-in that is in use, such as Flash, Quicktime, or Adobe Reader.  These processes just contain the plug-ins themselves, along with some glue code to let them interact with the browser and renderers.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">3. When should the browser create processes?</span></div><div><br /></div><div>Once Google Chrome has created its browser process, it will generally create one renderer process for each instance of a web site you visit.  This approach aims to keep pages from different web sites isolated from each other.</div><div><br /></div><div>You can think of this as using a different process for each tab in the browser, but allowing two tabs to share a process if they are related to each other and are showing the same site.  For example, if one tab opens another tab using JavaScript, or if you open a link to the same site in a new tab, the tabs will share a renderer process.  This lets the pages in these tabs communicate via JavaScript and share cached objects.  Conversely, if you type the URL of a different site into the location bar of a tab, we will swap in a new renderer process for the tab.</div><div><br /></div><div>Compatibility with existing web pages is important for us.  For this reason, we define a web site as a registered domain name, like google.com or bbc.co.uk.  This means we'll consider sub-domains like mail.google.com and maps.google.com as part of the same site.  This is necessary because there are cases where tabs from different sub-domains may try to communicate with each other via JavaScript, so we want to keep them in the same renderer process.</div><div><br /></div><div>There are a few caveats to this basic approach, however.  Your computer would start to slow down if we created too many processes, so we place a limit on the number of renderer processes that we create (20 in most cases).  Once we hit this limit, we'll start re-using the existing renderer processes for new tabs.  Thus, it's possible that the same renderer process could be used for more than one web site.  We also don't yet put cross-site frames in their own processes, and we don't yet swap a tab's renderer process for all types of cross-site navigations.  So far, we only swap a tab's process for navigations via the browser's "chrome," like the location bar or bookmarks.  Despite these caveats, Google Chrome will generally keep instances of different web sites isolated from each other in common usage.</div><div><br /></div><div>For each type of plug-in, Google Chrome will create a plug-in process when you first visit a page that uses it.  A short time after you close all pages using a particular plug-in, we will destroy its process.</div><div><br /></div><div>We'll post future blog entries as we refine our policies for creating and swapping among renderer processes.  In the mean time, we hope you see some of the benefits of a multi-process architecture when using Google Chrome.</div><div><br /></div><span class="post-author">Posted by Charlie Reis</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </noscript> </div> </div> <div class='share'> <span class='twitter-custom social-wrapper' data-href='http://twitter.com/share?text=Chromium Blog:Multi-process Architecture&url=https://blog.chromium.org/2008/09/multi-process-architecture.html&via=ChromiumDev'> <img alt='Share on Twitter' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png' width='24'/> </span> <span class='fb-custom social-wrapper' data-href='https://www.facebook.com/sharer.php?u=https://blog.chromium.org/2008/09/multi-process-architecture.html'> <img alt='Share on Facebook' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png' width='24'/> </span> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://blog.chromium.org/2008/09/multi-process-architecture.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> </div> </div> </div> <div class='post' data-id='7770298913975836255' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2008/09/security-architecture.html' itemprop='url' title='Security Architecture'> Security Architecture </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Wednesday, September 10, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <div>Chromium helps protect your computer from malware by running some parts of the browser in a sandbox.  The sandbox tries to limit what an attacker can do after exploiting a bug.  In particular, the sandbox aims to prevent malicious web sites from automatically installing software on your computer and from reading confidential files on your hard drive.</div><div><br /></div><div>The two main modules of Chromium are the browser process and the rendering engine.  The browser process has the same access to your computer that you do, so we try to reduce its attack surface by keeping it as simple as possible.  For example, the browser process does not attempt to understand HTML, JavaScript, or other complex parts of web pages.  The rendering engine does the heavy lifting: laying out web pages and running JavaScript.</div><div><br /></div><div>To access your hard drive or the network, the rendering engine must go through the browser process, which checks to make sure the request looks legitimate.  In a sense, the browser process acts like a supervisor that double-checks that the rendering engine is acting appropriately.  The sandbox doesn't prevent every kind of attack (for example, it doesn't stop phishing or cross-site scripting), but it should make it harder for attackers to get to your files.</div><div><br /></div><div>To see how well this architecture might mitigate future attacks, we studied recent vulnerabilities in web browsers.  We found that about 70% of the most serious vulnerabilities (those that let an attacker execute arbitrary code) were in the rendering engine.  Although "number of vulnerabilities" is not an ideal metric for evaluating security, these numbers do suggest that sandboxing the rendering engine is likely to help improve security.</div><div><br /></div><div>To learn more, check out our <a href="http://crypto.stanford.edu/websec/chromium/">technical report</a> on Chromium's security architecture.</div><div><br /></div><span class="post-author">Posted by Adam Barth, Collin Jackson, and Charlie Reis, Software Engineers</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <div>Chromium helps protect your computer from malware by running some parts of the browser in a sandbox.  The sandbox tries to limit what an attacker can do after exploiting a bug.  In particular, the sandbox aims to prevent malicious web sites from automatically installing software on your computer and from reading confidential files on your hard drive.</div><div><br /></div><div>The two main modules of Chromium are the browser process and the rendering engine.  The browser process has the same access to your computer that you do, so we try to reduce its attack surface by keeping it as simple as possible.  For example, the browser process does not attempt to understand HTML, JavaScript, or other complex parts of web pages.  The rendering engine does the heavy lifting: laying out web pages and running JavaScript.</div><div><br /></div><div>To access your hard drive or the network, the rendering engine must go through the browser process, which checks to make sure the request looks legitimate.  In a sense, the browser process acts like a supervisor that double-checks that the rendering engine is acting appropriately.  The sandbox doesn't prevent every kind of attack (for example, it doesn't stop phishing or cross-site scripting), but it should make it harder for attackers to get to your files.</div><div><br /></div><div>To see how well this architecture might mitigate future attacks, we studied recent vulnerabilities in web browsers.  We found that about 70% of the most serious vulnerabilities (those that let an attacker execute arbitrary code) were in the rendering engine.  Although "number of vulnerabilities" is not an ideal metric for evaluating security, these numbers do suggest that sandboxing the rendering engine is likely to help improve security.</div><div><br /></div><div>To learn more, check out our <a href="http://crypto.stanford.edu/websec/chromium/">technical report</a> on Chromium's security architecture.</div><div><br /></div><span class="post-author">Posted by Adam Barth, Collin Jackson, and Charlie Reis, Software Engineers</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </noscript> </div> </div> <div class='share'> <span class='twitter-custom social-wrapper' data-href='http://twitter.com/share?text=Chromium Blog:Security Architecture&url=https://blog.chromium.org/2008/09/security-architecture.html&via=ChromiumDev'> <img alt='Share on Twitter' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png' width='24'/> </span> <span class='fb-custom social-wrapper' data-href='https://www.facebook.com/sharer.php?u=https://blog.chromium.org/2008/09/security-architecture.html'> <img alt='Share on Facebook' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png' width='24'/> </span> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://blog.chromium.org/2008/09/security-architecture.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> </div> </div> </div> <div class='post' data-id='7793303175695939921' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2008/09/taking-suggestions-on-suggest.html' itemprop='url' title='Taking Suggestions on Suggest'> Taking Suggestions on Suggest </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Tuesday, September 9, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> Google Suggest is one of the things that makes the omnibox so cool. Just type a few letters and Google Chrome will often point you at the search query or the page that you were trying to type. Based on feedback from privacy groups, the Suggest team is making some changes to the information they log. You can <a href="http://googleblog.blogspot.com/2008/09/update-to-google-suggest.html">read more about it</a> on the Google Blog.<br /><br /><span class="post-author">Posted by Ian Fette, Product Manager</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> Google Suggest is one of the things that makes the omnibox so cool. Just type a few letters and Google Chrome will often point you at the search query or the page that you were trying to type. Based on feedback from privacy groups, the Suggest team is making some changes to the information they log. You can <a href="http://googleblog.blogspot.com/2008/09/update-to-google-suggest.html">read more about it</a> on the Google Blog.<br /><br /><span class="post-author">Posted by Ian Fette, Product Manager</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </noscript> </div> </div> <div class='share'> <span class='twitter-custom social-wrapper' data-href='http://twitter.com/share?text=Chromium Blog:Taking Suggestions on Suggest&url=https://blog.chromium.org/2008/09/taking-suggestions-on-suggest.html&via=ChromiumDev'> <img alt='Share on Twitter' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png' width='24'/> </span> <span class='fb-custom social-wrapper' data-href='https://www.facebook.com/sharer.php?u=https://blog.chromium.org/2008/09/taking-suggestions-on-suggest.html'> <img alt='Share on Facebook' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png' width='24'/> </span> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://blog.chromium.org/2008/09/taking-suggestions-on-suggest.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> </div> </div> </div> <div class='post' data-id='824351061585756141' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2008/09/chrome-3s-webkit.html' itemprop='url' title='Chrome <3s WebKit'> Chrome <3s WebKit </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Friday, September 5, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> Our recent launch of Google Chrome simply would not have been possible were it not for the awesome <a href="http://webkit.org/">WebKit</a> rendering engine and the <a href="//www.google.com/search?hl=en&q=cache:http://trac.webkit.org/wiki/WebKit%2520Team&btnG=Search">amazing team</a> behind it. We want to take a moment to recognize their excellent work (past and present!) and talk about how we arrived at incorporating WebKit into Google Chrome. By the way, that excellent <a href="http://twitter.com/perivision/statuses/907564759">web</a> <a href="http://twitter.com/mayhemchaos/statuses/908095530">inspector</a> <a href="http://twitter.com/JohnB/statuses/907242324">tool</a> is actually a <a href="http://webkit.org/blog/108/yet-another-one-more-thing-a-new-web-inspector/">component of WebKit</a> ;-)<br /><br />At the onset of the project, we knew we didn't want to create yet <span style="font-style: italic;">another</span> rendering engine. After all, web developers already have enough to worry about when it comes to making sure that all users can access their web pages and web applications. Being inside Google, where we develop lots of pages and webapps, we were very familiar with this problem!<br /><br />Yet, we also knew that we wanted to create a multi-process browser, which meant that our rendering engine needed to be very lightweight as we were going to be running many of them. Furthermore, in order to achieve our sandboxing objectives, the rendering engine needed to be stripped of any access to the local file system and native widget system.<br /><br />Our final constraint involved our open source ambitions for Google Chrome. We needed a rendering engine that was open source.<br /><br />WebKit became the obvious solution after talking to fellow engineers working on the Android project. They were already using WebKit (as it is a great option for mobile devices), and they trumpeted its speed, flexibility and simplicity. We routinely heard comments like "It's so easy to hack!" and "It didn't take me long to find my way around the code base."<br /><br />Our next step was to put together a test app, that allowed us to try WebKit out in a basic multi-process configuration. We were blown away by how fast WebKit could render pages! You can see a simple example of this in our <a href="//www.youtube.com/watch?v=1d1_ool4r7s">press conference video</a> (advance to the 38:30 mark). The bottom line: WebKit is a big reason why Chrome feels fast.<br /><br />We continued tracking the WebKit tip-of-tree during the development of Google Chrome. Now that Chromium.org is live, all of our source code is available there, and we are busily working to contribute our modifications back upstream to WebKit. We are excited about all the cool things coming in WebKit and can't wait to start helping out in a big way.<br /><br />Thanks again to everyone who worked on WebKit. You guys rock!<br /><br /><span class="post-author">Posted by Darin Fisher, Software Engineer<br /></span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> Our recent launch of Google Chrome simply would not have been possible were it not for the awesome <a href="http://webkit.org/">WebKit</a> rendering engine and the <a href="//www.google.com/search?hl=en&q=cache:http://trac.webkit.org/wiki/WebKit%2520Team&btnG=Search">amazing team</a> behind it. We want to take a moment to recognize their excellent work (past and present!) and talk about how we arrived at incorporating WebKit into Google Chrome. By the way, that excellent <a href="http://twitter.com/perivision/statuses/907564759">web</a> <a href="http://twitter.com/mayhemchaos/statuses/908095530">inspector</a> <a href="http://twitter.com/JohnB/statuses/907242324">tool</a> is actually a <a href="http://webkit.org/blog/108/yet-another-one-more-thing-a-new-web-inspector/">component of WebKit</a> ;-)<br /><br />At the onset of the project, we knew we didn't want to create yet <span style="font-style: italic;">another</span> rendering engine. After all, web developers already have enough to worry about when it comes to making sure that all users can access their web pages and web applications. Being inside Google, where we develop lots of pages and webapps, we were very familiar with this problem!<br /><br />Yet, we also knew that we wanted to create a multi-process browser, which meant that our rendering engine needed to be very lightweight as we were going to be running many of them. Furthermore, in order to achieve our sandboxing objectives, the rendering engine needed to be stripped of any access to the local file system and native widget system.<br /><br />Our final constraint involved our open source ambitions for Google Chrome. We needed a rendering engine that was open source.<br /><br />WebKit became the obvious solution after talking to fellow engineers working on the Android project. They were already using WebKit (as it is a great option for mobile devices), and they trumpeted its speed, flexibility and simplicity. We routinely heard comments like "It's so easy to hack!" and "It didn't take me long to find my way around the code base."<br /><br />Our next step was to put together a test app, that allowed us to try WebKit out in a basic multi-process configuration. We were blown away by how fast WebKit could render pages! You can see a simple example of this in our <a href="//www.youtube.com/watch?v=1d1_ool4r7s">press conference video</a> (advance to the 38:30 mark). The bottom line: WebKit is a big reason why Chrome feels fast.<br /><br />We continued tracking the WebKit tip-of-tree during the development of Google Chrome. Now that Chromium.org is live, all of our source code is available there, and we are busily working to contribute our modifications back upstream to WebKit. We are excited about all the cool things coming in WebKit and can't wait to start helping out in a big way.<br /><br />Thanks again to everyone who worked on WebKit. You guys rock!<br /><br /><span class="post-author">Posted by Darin Fisher, Software Engineer<br /></span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </noscript> </div> </div> <div class='share'> <span class='twitter-custom social-wrapper' data-href='http://twitter.com/share?text=Chromium Blog:Chrome <3s WebKit&url=https://blog.chromium.org/2008/09/chrome-3s-webkit.html&via=ChromiumDev'> <img alt='Share on Twitter' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png' width='24'/> </span> <span class='fb-custom social-wrapper' data-href='https://www.facebook.com/sharer.php?u=https://blog.chromium.org/2008/09/chrome-3s-webkit.html'> <img alt='Share on Facebook' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png' width='24'/> </span> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://blog.chromium.org/2008/09/chrome-3s-webkit.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> </div> </div> </div> <div class='post' data-id='2826203398743548679' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2008/09/google-chromes-need-for-speed_02.html' itemprop='url' title='Google Chrome's Need for Speed'> Google Chrome's Need for Speed </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Tuesday, September 2, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> Ever since we opened the Google office in Aarhus, Denmark, I've been bombarded with the same question. What kind of virtual machine are you working on? Finally, I'm able to answer.<br />It is an open source JavaScript engine and it is fast.<br /><br />A core part of any web browser is its JavaScript engine. Web applications cannot be responsive and stable without a fast and reliable JavaScript engine. Google Chrome features a new JavaScript engine, V8, that has been designed for performance from the ground up. In particular, we wanted to remove some common bottlenecks that limit the amount and complexity of JavaScript code that can be used in Web applications.<br /><br />The cornerstones of the V8 design are:<br /><ul><li>Compilation of JavaScript source code directly into native machine code.</li><li>An efficient memory management system resulting in fast object allocation and small garbage collection pauses.</li><li> Introduction of hidden classes and inline caches that speed up property access and function calls.</li></ul>Virtual machines for object oriented languages have in the past used inline caching to speed up execution. However, this relies on objects with similar structure share the same runtime type.<br />By dynamically creating hidden classes for JavaScript objects, V8 can apply optimizations only possible in virtual machines with runtime types.<br /><br />More design details can be found here: <a href="http://code.google.com/apis/v8/design.html">http://code.google.com/apis/v8/design.html</a>.<br /><br />Along with V8 we have released a benchmark suite that reflects the kind of code we want to run fast: well-structured object-based applications with abstraction layers and many property accesses. As Web applications grow, we believe this suite will be representative of how Web developers write JavaScript code.<br /><br />The V8 benchmark suite consists of five medium sized standalone JavaScript applications: Richards, DeltaBlue, Crypto, RayTrace, and EarleyBoyer. A total more than 11,000 lines of JavaScript code. Web applications often spend considerable time waiting for the network connection, manipulating the DOM, and rendering pages. The V8 benchmark suite only measures pure JavaScript execution. Visit <a href="http://code.google.com/apis/v8/benchmarks.html">http://code.google.com/apis/v8/benchmarks.html</a> to see how to run the suite.<br /><br />I hope the web community will adopt the code and the ideas we have developed to advance the performance of JavaScript. Raising the performance bar of JavaScript is important for continued innovation of web applications.<br /><br />V8 is an open source project and we encourage developers to visit <a href="http://code.google.com/p/v8">http://code.google.com/p/v8</a>.<br /><br /><font class="post-author">Posted by Lars Bak, Software Engineer </font> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> Ever since we opened the Google office in Aarhus, Denmark, I've been bombarded with the same question. What kind of virtual machine are you working on? Finally, I'm able to answer.<br />It is an open source JavaScript engine and it is fast.<br /><br />A core part of any web browser is its JavaScript engine. Web applications cannot be responsive and stable without a fast and reliable JavaScript engine. Google Chrome features a new JavaScript engine, V8, that has been designed for performance from the ground up. In particular, we wanted to remove some common bottlenecks that limit the amount and complexity of JavaScript code that can be used in Web applications.<br /><br />The cornerstones of the V8 design are:<br /><ul><li>Compilation of JavaScript source code directly into native machine code.</li><li>An efficient memory management system resulting in fast object allocation and small garbage collection pauses.</li><li> Introduction of hidden classes and inline caches that speed up property access and function calls.</li></ul>Virtual machines for object oriented languages have in the past used inline caching to speed up execution. However, this relies on objects with similar structure share the same runtime type.<br />By dynamically creating hidden classes for JavaScript objects, V8 can apply optimizations only possible in virtual machines with runtime types.<br /><br />More design details can be found here: <a href="http://code.google.com/apis/v8/design.html">http://code.google.com/apis/v8/design.html</a>.<br /><br />Along with V8 we have released a benchmark suite that reflects the kind of code we want to run fast: well-structured object-based applications with abstraction layers and many property accesses. As Web applications grow, we believe this suite will be representative of how Web developers write JavaScript code.<br /><br />The V8 benchmark suite consists of five medium sized standalone JavaScript applications: Richards, DeltaBlue, Crypto, RayTrace, and EarleyBoyer. A total more than 11,000 lines of JavaScript code. Web applications often spend considerable time waiting for the network connection, manipulating the DOM, and rendering pages. The V8 benchmark suite only measures pure JavaScript execution. Visit <a href="http://code.google.com/apis/v8/benchmarks.html">http://code.google.com/apis/v8/benchmarks.html</a> to see how to run the suite.<br /><br />I hope the web community will adopt the code and the ideas we have developed to advance the performance of JavaScript. Raising the performance bar of JavaScript is important for continued innovation of web applications.<br /><br />V8 is an open source project and we encourage developers to visit <a href="http://code.google.com/p/v8">http://code.google.com/p/v8</a>.<br /><br /><font class="post-author">Posted by Lars Bak, Software Engineer </font> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </noscript> </div> </div> <div class='share'> <span class='twitter-custom social-wrapper' data-href='http://twitter.com/share?text=Chromium Blog:Google Chrome's Need for Speed&url=https://blog.chromium.org/2008/09/google-chromes-need-for-speed_02.html&via=ChromiumDev'> <img alt='Share on Twitter' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png' width='24'/> </span> <span class='fb-custom social-wrapper' data-href='https://www.facebook.com/sharer.php?u=https://blog.chromium.org/2008/09/google-chromes-need-for-speed_02.html'> <img alt='Share on Facebook' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png' width='24'/> </span> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://blog.chromium.org/2008/09/google-chromes-need-for-speed_02.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> </div> </div> </div> <div class='post' data-id='588666672787863513' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2008/09/welcome-to-chromium_02.html' itemprop='url' title='Welcome to Chromium'> Welcome to Chromium </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Tuesday, September 2, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <div>Today, Google launched a new web browser called <a href="//www.google.com/chrome">Google Chrome</a>. At the same time, we are releasing all of the code as open source under a permissive BSD license. The open source project is called Chromium - after the metal used to make chrome.</div><div><br /></div><div>Why did Google release the source code?</div><div><br /></div><div>Primarily it's because one of the fundamental goals of the Chromium project is to help drive the web forward. Open source projects like <a href="http://www.mozilla.org/">Firefox</a> and <a href="http://www.webkit.org/">WebKit</a> have led the way in defining the next generation of web technologies and standards, and we felt the best way we could help was to follow suit, and be as open as we could. To be clear, improving the web in this way also has some clear benefits for us as a company. With a richer set of APIs we can build more interesting apps allowing people to do more online. The more people do online, the more they can use our services. At any rate, we have worked on this project by ourselves for long enough - it's time for us to engage with the wider web community so that we can move on to the next set of challenges.</div><div><br /></div><div>We believe that open source works not only because it allows people to join us and improve our products, but also (and more importantly) because it means other projects are able to use the code we've developed. Where we've developed innovative new technology, we hope that other projects can use it to make their products better, just as we've been able to adopt code from other open source projects to make our product better.</div><div><br /></div><div>How will we be working with the open source community?</div><div><br /></div><div>To begin with, we are engaging with the WebKit community to integrate our patches back into the main line of WebKit development. Because of Chromium's unique <a href="http://dev.chromium.org/developers/design-documents/multi-process-architecture">multi-process architecture</a>, the integration of the <a href="http://code.google.com/p/v8/">V8 JavaScript engine</a>, and other factors, we've built a fairly significant port of WebKit on Windows, and are developing the same for Mac OS X and Linux. We want to make sure that we can find a productive way to integrate and sync up with the WebKit community in this effort as we move forward.</div><div><br /></div><div>Today, you can visit our project website at <a href="http://www.chromium.org/">www.chromium.org</a>, where you can get the latest source code or the freshest development build. If you're interested in keeping track of what's going on, you can join one of our <a href="http://dev.chromium.org/developers/discussion-groups">discussion groups</a>, where you can participate in development discussions and keep track of bugs as they're filed and fixed. Maybe you'll want to fix a few, too! You'll also find information on reporting bugs and all the various other aspects of the project. We hope you'll check it out!</div><div><br /></div><div>This is the Chromium blog. The posts here will be of a mostly technical nature, discussing the design theory and implementation details of work we've done or are doing. Over the next few weeks there'll be a number of posts that give a high level tour of the most important aspects of the browser.</div><div><br /></div><div>Finally, if you've not yet done so, take Google Chrome for a spin. You can download it from <a href="//www.google.com/chrome/">http://www.google.com/chrome/</a>.</div><div><br /></div><br /><span class="post-author">Posted by Ben Goodger, Software Engineer</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <div>Today, Google launched a new web browser called <a href="//www.google.com/chrome">Google Chrome</a>. At the same time, we are releasing all of the code as open source under a permissive BSD license. The open source project is called Chromium - after the metal used to make chrome.</div><div><br /></div><div>Why did Google release the source code?</div><div><br /></div><div>Primarily it's because one of the fundamental goals of the Chromium project is to help drive the web forward. Open source projects like <a href="http://www.mozilla.org/">Firefox</a> and <a href="http://www.webkit.org/">WebKit</a> have led the way in defining the next generation of web technologies and standards, and we felt the best way we could help was to follow suit, and be as open as we could. To be clear, improving the web in this way also has some clear benefits for us as a company. With a richer set of APIs we can build more interesting apps allowing people to do more online. The more people do online, the more they can use our services. At any rate, we have worked on this project by ourselves for long enough - it's time for us to engage with the wider web community so that we can move on to the next set of challenges.</div><div><br /></div><div>We believe that open source works not only because it allows people to join us and improve our products, but also (and more importantly) because it means other projects are able to use the code we've developed. Where we've developed innovative new technology, we hope that other projects can use it to make their products better, just as we've been able to adopt code from other open source projects to make our product better.</div><div><br /></div><div>How will we be working with the open source community?</div><div><br /></div><div>To begin with, we are engaging with the WebKit community to integrate our patches back into the main line of WebKit development. Because of Chromium's unique <a href="http://dev.chromium.org/developers/design-documents/multi-process-architecture">multi-process architecture</a>, the integration of the <a href="http://code.google.com/p/v8/">V8 JavaScript engine</a>, and other factors, we've built a fairly significant port of WebKit on Windows, and are developing the same for Mac OS X and Linux. We want to make sure that we can find a productive way to integrate and sync up with the WebKit community in this effort as we move forward.</div><div><br /></div><div>Today, you can visit our project website at <a href="http://www.chromium.org/">www.chromium.org</a>, where you can get the latest source code or the freshest development build. If you're interested in keeping track of what's going on, you can join one of our <a href="http://dev.chromium.org/developers/discussion-groups">discussion groups</a>, where you can participate in development discussions and keep track of bugs as they're filed and fixed. Maybe you'll want to fix a few, too! You'll also find information on reporting bugs and all the various other aspects of the project. We hope you'll check it out!</div><div><br /></div><div>This is the Chromium blog. The posts here will be of a mostly technical nature, discussing the design theory and implementation details of work we've done or are doing. Over the next few weeks there'll be a number of posts that give a high level tour of the most important aspects of the browser.</div><div><br /></div><div>Finally, if you've not yet done so, take Google Chrome for a spin. You can download it from <a href="//www.google.com/chrome/">http://www.google.com/chrome/</a>.</div><div><br /></div><br /><span class="post-author">Posted by Ben Goodger, Software Engineer</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </noscript> </div> </div> <div class='share'> <span class='twitter-custom social-wrapper' data-href='http://twitter.com/share?text=Chromium Blog:Welcome to Chromium&url=https://blog.chromium.org/2008/09/welcome-to-chromium_02.html&via=ChromiumDev'> <img alt='Share on Twitter' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png' width='24'/> </span> <span class='fb-custom social-wrapper' data-href='https://www.facebook.com/sharer.php?u=https://blog.chromium.org/2008/09/welcome-to-chromium_02.html'> <img alt='Share on Facebook' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png' width='24'/> </span> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://blog.chromium.org/2008/09/welcome-to-chromium_02.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> </div> </div> </div> <div class='blog-pager' id='blog-pager'> <a class='home-link' href='https://blog.chromium.org/'> <i class='material-icons'>  </i> </a> <span id='blog-pager-newer-link'> <a class='blog-pager-newer-link' href='https://blog.chromium.org/search?updated-max=2009-02-25T15:41:00-08:00&max-results=7&reverse-paginate=true' id='Blog1_blog-pager-newer-link' title='Newer Posts'> <i class='material-icons'>  </i> </a> </span> <i class='material-icons disabled'>  </i> </div> <div class='clear'></div> </div></div> </div> </div> <div class='col-right'> <div class='section' id='sidebar-top'><div class='widget HTML' data-version='1' id='HTML8'> <div class='widget-content'> <div class='searchBox'> <input type='text' title='Search This Blog' placeholder='Search blog ...' /> </div> </div> <div class='clear'></div> </div></div> <div id='aside'> <div class='section' id='sidebar'><div class='widget Label' data-version='1' id='Label1'> <div class='tab'> <img class='sidebar-icon' src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAYpJREFUeNrs2aFuwzAQBmAvKRkMKRjZA4QMDJaWFgyMjuzFRg37DIUlA3uFkoGQSaWzJU+tpri5O9+l/zSfdFJlpe59yTmyVedq1PjfcZMZ70NuQnaF8w8htyE/rABtpviXkLcK88c5HhLkMBfgVan43zfFBNGMjHVGT/s55KP2pAvidbGHd+nzKt1RKSLG3rKF1iPFv6UWiPke8i7kEqGdGsI1O+LYVdqJAjgirwkKYD0ytkJBUNbAMvX8V3q9PhUsYvU1sWD8SO/sQvx2ahxOiNoJCSBCoAHYCEQAC4EKICOQASQEOmAS8RcAFxFN5hiIiugpgC3wk9hQAHH/70EBHXUN7IER5EWMiBgo2+nzOKQv9SCAeEM/OQAkhE/ncccFICB87qzQMia5FsJfOui0zMnmRvipU1ormHQuxGTxUsAcCFLxJQBLBLn4UoAFglW8BkATwS5eC6CBEBWvCShBiIvXBkgQRcVbADiI4uKtABSESvGWgB9EzHt3+tNwyO0qa9SoIYtvAQYAqDJhaWWeMecAAAAASUVORK5CYII='/> <h2> Labels </h2> <i class='material-icons arrow'>  </i> </div> <div class='widget-content list-label-widget-content'> <ul> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/%24200K'> $200K </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/10th%20birthday'> 10th birthday </a> <span dir='ltr'> 4 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/abusive%20ads'> abusive ads </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/abusive%20notifications'> abusive notifications </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/accessibility'> accessibility </a> <span dir='ltr'> 3 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/ad%20blockers'> ad blockers </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/ad%20blocking'> ad blocking </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/advanced%20capabilities'> advanced capabilities </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/android'> android </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/anti%20abuse'> anti abuse </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/anti-deception'> anti-deception </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/background%20periodic%20sync'> background periodic sync </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/badging'> badging </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/benchmarks'> benchmarks </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/beta'> beta </a> <span dir='ltr'> 83 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/better%20ads%20standards'> better ads standards </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/billing'> billing </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/birthday'> birthday </a> <span dir='ltr'> 4 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/blink'> blink </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/browser'> browser </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/browser%20interoperability'> browser interoperability </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/bundles'> bundles </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/capabilities'> capabilities </a> <span dir='ltr'> 6 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/capable%20web'> capable web </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/cds'> cds </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/cds18'> cds18 </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/cds2018'> cds2018 </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/chrome'> chrome </a> <span dir='ltr'> 35 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/chrome%2081'> chrome 81 </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/chrome%2083'> chrome 83 </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/chrome%2084'> chrome 84 </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/chrome%20ads'> chrome ads </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/chrome%20apps'> chrome apps </a> <span dir='ltr'> 5 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/Chrome%20dev'> Chrome dev </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/chrome%20dev%20summit'> chrome dev summit </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/chrome%20dev%20summit%202018'> chrome dev summit 2018 </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/chrome%20dev%20summit%202019'> chrome dev summit 2019 </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/chrome%20developer'> chrome developer </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/Chrome%20Developer%20Center'> Chrome Developer Center </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/chrome%20developer%20summit'> chrome developer summit </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/chrome%20devtools'> chrome devtools </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/Chrome%20extension'> Chrome extension </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/chrome%20extensions'> chrome extensions </a> <span dir='ltr'> 3 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/Chrome%20Frame'> Chrome Frame </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/Chrome%20lite'> Chrome lite </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/Chrome%20on%20Android'> Chrome on Android </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/chrome%20on%20ios'> chrome on ios </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/Chrome%20on%20Mac'> Chrome on Mac </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/Chrome%20OS'> Chrome OS </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/chrome%20privacy'> chrome privacy </a> <span dir='ltr'> 4 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/chrome%20releases'> chrome releases </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/chrome%20security'> chrome security </a> <span dir='ltr'> 10 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/chrome%20web%20store'> chrome web store </a> <span dir='ltr'> 32 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/chromedevtools'> chromedevtools </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/chromeframe'> chromeframe </a> <span dir='ltr'> 3 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/chromeos'> chromeos </a> <span dir='ltr'> 4 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/chromeos.dev'> chromeos.dev </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/chromium'> chromium </a> <span dir='ltr'> 9 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/cloud%20print'> cloud print </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/coalition'> coalition </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/coalition%20for%20better%20ads'> coalition for better ads </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/contact%20picker'> contact picker </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/content%20indexing'> content indexing </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/cookies'> cookies </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/core%20web%20vitals'> core web vitals </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/csrf'> csrf </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/css'> css </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/cumulative%20layout%20shift'> cumulative layout shift </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/custom%20tabs'> custom tabs </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/dart'> dart </a> <span dir='ltr'> 8 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/dashboard'> dashboard </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/Data%20Saver'> Data Saver </a> <span dir='ltr'> 3 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/Data%20saver%20desktop%20extension'> Data saver desktop extension </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/day%202'> day 2 </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/deceptive%20installation'> deceptive installation </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/declarative%20net%20request%20api'> declarative net request api </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/design'> design </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/developer%20dashboard'> developer dashboard </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/Developer%20Program%20Policy'> Developer Program Policy </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/developer%20website'> developer website </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/devtools'> devtools </a> <span dir='ltr'> 13 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/digital%20event'> digital event </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/discoverability'> discoverability </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/DNS-over-HTTPS'> DNS-over-HTTPS </a> <span dir='ltr'> 4 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/DoH'> DoH </a> <span dir='ltr'> 4 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/emoji'> emoji </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/emscriptem'> emscriptem </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/enterprise'> enterprise </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/extensions'> extensions </a> <span dir='ltr'> 27 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/Fast%20badging'> Fast badging </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/faster%20web'> faster web </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/features'> features </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/feedback'> feedback </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/field%20data'> field data </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/first%20input%20delay'> first input delay </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/Follow'> Follow </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/fonts'> fonts </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/form%20controls'> form controls </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/frameworks'> frameworks </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/fugu'> fugu </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/fund'> fund </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/funding'> funding </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/gdd'> gdd </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/google%20earth'> google earth </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/google%20event'> google event </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/google%20io%202019'> google io 2019 </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/google%20web%20developer'> google web developer </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/googlechrome'> googlechrome </a> <span dir='ltr'> 12 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/harmful%20ads'> harmful ads </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/html5'> html5 </a> <span dir='ltr'> 11 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/HTTP%2F3'> HTTP/3 </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/HTTPS'> HTTPS </a> <span dir='ltr'> 4 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/iframes'> iframes </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/images'> images </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/incognito'> incognito </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/insecure%20forms'> insecure forms </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/intent%20to%20explain'> intent to explain </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/ios'> ios </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/ios%20Chrome'> ios Chrome </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/issue%20tracker'> issue tracker </a> <span dir='ltr'> 3 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/jank'> jank </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/javascript'> javascript </a> <span dir='ltr'> 5 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/lab%20data'> lab data </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/labelling'> labelling </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/largest%20contentful%20paint'> largest contentful paint </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/launch'> launch </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/lazy-loading'> lazy-loading </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/lighthouse'> lighthouse </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/linux'> linux </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/Lite%20Mode'> Lite Mode </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/Lite%20pages'> Lite pages </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/loading%20interventions'> loading interventions </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/loading%20optimizations'> loading optimizations </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/lock%20icon'> lock icon </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/long-tail'> long-tail </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/mac'> mac </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/manifest%20v3'> manifest v3 </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/metrics'> metrics </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/microsoft%20edge'> microsoft edge </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/mixed%20forms'> mixed forms </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/mobile'> mobile </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/na'> na </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/native%20client'> native client </a> <span dir='ltr'> 8 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/native%20file%20system'> native file system </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/New%20Features'> New Features </a> <span dir='ltr'> 5 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/notifications'> notifications </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/octane'> octane </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/open%20web'> open web </a> <span dir='ltr'> 4 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/origin%20trials'> origin trials </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/pagespeed%20insights'> pagespeed insights </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/pagespeedinsights'> pagespeedinsights </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/passwords'> passwords </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/payment%20handler'> payment handler </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/payment%20request'> payment request </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/payments'> payments </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/performance'> performance </a> <span dir='ltr'> 20 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/performance%20tools'> performance tools </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/permission%20UI'> permission UI </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/permissions'> permissions </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/play%20store'> play store </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/portals'> portals </a> <span dir='ltr'> 3 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/prefetching'> prefetching </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/privacy'> privacy </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/privacy%20sandbox'> privacy sandbox </a> <span dir='ltr'> 4 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/private%20prefetch%20proxy'> private prefetch proxy </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/profile%20guided%20optimization'> profile guided optimization </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/progressive%20web%20apps'> progressive web apps </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/Project%20Strobe'> Project Strobe </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/protection'> protection </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/pwa'> pwa </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/QUIC'> QUIC </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/quieter%20permissions'> quieter permissions </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/releases'> releases </a> <span dir='ltr'> 3 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/removals'> removals </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/rlz'> rlz </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/root%20program'> root program </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/safe%20browsing'> safe browsing </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/Secure%20DNS'> Secure DNS </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/security'> security </a> <span dir='ltr'> 36 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/site%20isolation'> site isolation </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/slow%20loading'> slow loading </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/sms%20receiver'> sms receiver </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/spam%20policy'> spam policy </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/spdy'> spdy </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/spectre'> spectre </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/speed'> speed </a> <span dir='ltr'> 4 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/ssl'> ssl </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/store%20listing'> store listing </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/strobe'> strobe </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/subscription%20pages'> subscription pages </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/suspicious%20site%20reporter%20extension'> suspicious site reporter extension </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/TCP'> TCP </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/the%20fast%20and%20the%20curious'> the fast and the curious </a> <span dir='ltr'> 23 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/TLS'> TLS </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/tools'> tools </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/tracing'> tracing </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/transparency'> transparency </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/trusted%20web%20activities'> trusted web activities </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/twa'> twa </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/user%20agent%20string'> user agent string </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/user%20data%20policy'> user data policy </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/v8'> v8 </a> <span dir='ltr'> 6 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/video'> video </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/wasm'> wasm </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/web'> web </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/web%20apps'> web apps </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/web%20assembly'> web assembly </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/web%20developers'> web developers </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/web%20intents'> web intents </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/web%20packaging'> web packaging </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/web%20payments'> web payments </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/web%20platform'> web platform </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/web%20request%20api'> web request api </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/web%20vitals'> web vitals </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/web.dev'> web.dev </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/web.dev%20live'> web.dev live </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/webapi'> webapi </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/webassembly'> webassembly </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/webaudio'> webaudio </a> <span dir='ltr'> 3 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/webgl'> webgl </a> <span dir='ltr'> 7 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/webkit'> webkit </a> <span dir='ltr'> 5 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/WebM'> WebM </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/webmaster'> webmaster </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/webp'> webp </a> <span dir='ltr'> 5 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/webrtc'> webrtc </a> <span dir='ltr'> 6 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/websockets'> websockets </a> <span dir='ltr'> 5 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/webtiming'> webtiming </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/writable-files'> writable-files </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://blog.chromium.org/search/label/yerba%20beuna%20center%20for%20the%20arts'> yerba beuna center for the arts </a> <span dir='ltr'> 1 </span> </li> </ul> <div class='clear'></div> </div> </div><div class='widget BlogArchive' data-version='1' id='BlogArchive1'> <div class='tab'> <i class='material-icons icon'>  </i> <h2> Archive </h2> <i class='material-icons arrow'>  </i> </div> <div class='widget-content'> <div id='ArchiveList'> <div id='BlogArchive1_ArchiveList'> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class='intervalToggle'> <span class='new-toggle' href='javascript:void(0)'> <i class='material-icons arrow'>  </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'>  </i>   </span> </a> <a class='post-count-link' href='https://blog.chromium.org/2024/'> 2024 </a> </div> <div class='items'> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2024/08/'> Aug </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2024/06/'> Jun </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2024/05/'> May </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2024/04/'> Apr </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2024/03/'> Mar </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2024/02/'> Feb </a> </div> <div class='items'> </div> </li> </ul> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class='intervalToggle'> <span class='new-toggle' href='javascript:void(0)'> <i class='material-icons arrow'>  </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'>  </i>   </span> </a> <a class='post-count-link' href='https://blog.chromium.org/2023/'> 2023 </a> </div> <div class='items'> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2023/11/'> Nov </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2023/10/'> Oct </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2023/09/'> Sep </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2023/08/'> Aug </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2023/06/'> Jun </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2023/05/'> May </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2023/04/'> Apr </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2023/02/'> Feb </a> </div> <div class='items'> </div> </li> </ul> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class='intervalToggle'> <span class='new-toggle' href='javascript:void(0)'> <i class='material-icons arrow'>  </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'>  </i>   </span> </a> <a class='post-count-link' href='https://blog.chromium.org/2022/'> 2022 </a> </div> <div class='items'> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2022/12/'> Dec </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2022/09/'> Sep </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2022/08/'> Aug </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2022/06/'> Jun </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2022/05/'> May </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2022/04/'> Apr </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2022/03/'> Mar </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2022/02/'> Feb </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2022/01/'> Jan </a> </div> <div class='items'> </div> </li> </ul> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class='intervalToggle'> <span class='new-toggle' href='javascript:void(0)'> <i class='material-icons arrow'>  </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'>  </i>   </span> </a> <a class='post-count-link' href='https://blog.chromium.org/2021/'> 2021 </a> </div> <div class='items'> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2021/12/'> Dec </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2021/11/'> Nov </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2021/10/'> Oct </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2021/09/'> Sep </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2021/08/'> Aug </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2021/07/'> Jul </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2021/06/'> Jun </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2021/05/'> May </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2021/04/'> Apr </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2021/03/'> Mar </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2021/02/'> Feb </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2021/01/'> Jan </a> </div> <div class='items'> </div> </li> </ul> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class='intervalToggle'> <span class='new-toggle' href='javascript:void(0)'> <i class='material-icons arrow'>  </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'>  </i>   </span> </a> <a class='post-count-link' href='https://blog.chromium.org/2020/'> 2020 </a> </div> <div class='items'> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2020/12/'> Dec </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2020/11/'> Nov </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2020/10/'> Oct </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2020/09/'> Sep </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2020/08/'> Aug </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2020/07/'> Jul </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2020/06/'> Jun </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2020/05/'> May </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2020/04/'> Apr </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2020/03/'> Mar </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2020/02/'> Feb </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2020/01/'> Jan </a> </div> <div class='items'> </div> </li> </ul> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class='intervalToggle'> <span class='new-toggle' href='javascript:void(0)'> <i class='material-icons arrow'>  </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'>  </i>   </span> </a> <a class='post-count-link' href='https://blog.chromium.org/2019/'> 2019 </a> </div> <div class='items'> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2019/12/'> Dec </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2019/11/'> Nov </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2019/10/'> Oct </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2019/09/'> Sep </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2019/08/'> Aug </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2019/07/'> Jul </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2019/06/'> Jun </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2019/05/'> May </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2019/04/'> Apr </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2019/03/'> Mar </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2019/02/'> Feb </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2019/01/'> Jan </a> </div> <div class='items'> </div> </li> </ul> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class='intervalToggle'> <span class='new-toggle' href='javascript:void(0)'> <i class='material-icons arrow'>  </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'>  </i>   </span> </a> <a class='post-count-link' href='https://blog.chromium.org/2018/'> 2018 </a> </div> <div class='items'> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2018/12/'> Dec </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2018/11/'> Nov </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2018/10/'> Oct </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2018/09/'> Sep </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2018/08/'> Aug </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2018/07/'> Jul </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2018/06/'> Jun </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2018/05/'> May </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2018/04/'> Apr </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2018/03/'> Mar </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2018/02/'> Feb </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2018/01/'> Jan </a> </div> <div class='items'> </div> </li> </ul> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class='intervalToggle'> <span class='new-toggle' href='javascript:void(0)'> <i class='material-icons arrow'>  </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'>  </i>   </span> </a> <a class='post-count-link' href='https://blog.chromium.org/2017/'> 2017 </a> </div> <div class='items'> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2017/12/'> Dec </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2017/11/'> Nov </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2017/10/'> Oct </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2017/09/'> Sep </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2017/08/'> Aug </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2017/07/'> Jul </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2017/06/'> Jun </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2017/05/'> May </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2017/04/'> Apr </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2017/03/'> Mar </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2017/02/'> Feb </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2017/01/'> Jan </a> </div> <div class='items'> </div> </li> </ul> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class='intervalToggle'> <span class='new-toggle' href='javascript:void(0)'> <i class='material-icons arrow'>  </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'>  </i>   </span> </a> <a class='post-count-link' href='https://blog.chromium.org/2016/'> 2016 </a> </div> <div class='items'> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2016/12/'> Dec </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2016/11/'> Nov </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2016/10/'> Oct </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2016/09/'> Sep </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2016/08/'> Aug </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2016/06/'> Jun </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2016/05/'> May </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2016/04/'> Apr </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2016/03/'> Mar </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2016/02/'> Feb </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2016/01/'> Jan </a> </div> <div class='items'> </div> </li> </ul> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class='intervalToggle'> <span class='new-toggle' href='javascript:void(0)'> <i class='material-icons arrow'>  </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'>  </i>   </span> </a> <a class='post-count-link' href='https://blog.chromium.org/2015/'> 2015 </a> </div> <div class='items'> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2015/12/'> Dec </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2015/11/'> Nov </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2015/10/'> Oct </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2015/09/'> Sep </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2015/08/'> Aug </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2015/07/'> Jul </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2015/06/'> Jun </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2015/05/'> May </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2015/04/'> Apr </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2015/03/'> Mar </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2015/02/'> Feb </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2015/01/'> Jan </a> </div> <div class='items'> </div> </li> </ul> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class='intervalToggle'> <span class='new-toggle' href='javascript:void(0)'> <i class='material-icons arrow'>  </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'>  </i>   </span> </a> <a class='post-count-link' href='https://blog.chromium.org/2014/'> 2014 </a> </div> <div class='items'> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2014/12/'> Dec </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2014/11/'> Nov </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2014/10/'> Oct </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2014/09/'> Sep </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2014/08/'> Aug </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2014/07/'> Jul </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2014/06/'> Jun </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2014/05/'> May </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2014/04/'> Apr </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2014/03/'> Mar </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2014/02/'> Feb </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2014/01/'> Jan </a> </div> <div class='items'> </div> </li> </ul> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class='intervalToggle'> <span class='new-toggle' href='javascript:void(0)'> <i class='material-icons arrow'>  </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'>  </i>   </span> </a> <a class='post-count-link' href='https://blog.chromium.org/2013/'> 2013 </a> </div> <div class='items'> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2013/12/'> Dec </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2013/11/'> Nov </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2013/10/'> Oct </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2013/09/'> Sep </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2013/08/'> Aug </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2013/07/'> Jul </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2013/06/'> Jun </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2013/05/'> May </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2013/04/'> Apr </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2013/03/'> Mar </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2013/02/'> Feb </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2013/01/'> Jan </a> </div> <div class='items'> </div> </li> </ul> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class='intervalToggle'> <span class='new-toggle' href='javascript:void(0)'> <i class='material-icons arrow'>  </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'>  </i>   </span> </a> <a class='post-count-link' href='https://blog.chromium.org/2012/'> 2012 </a> </div> <div class='items'> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2012/12/'> Dec </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2012/11/'> Nov </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2012/10/'> Oct </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2012/09/'> Sep </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2012/08/'> Aug </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2012/07/'> Jul </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2012/06/'> Jun </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2012/05/'> May </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2012/04/'> Apr </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2012/03/'> Mar </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2012/02/'> Feb </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2012/01/'> Jan </a> </div> <div class='items'> </div> </li> </ul> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class='intervalToggle'> <span class='new-toggle' href='javascript:void(0)'> <i class='material-icons arrow'>  </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'>  </i>   </span> </a> <a class='post-count-link' href='https://blog.chromium.org/2011/'> 2011 </a> </div> <div class='items'> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2011/12/'> Dec </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2011/11/'> Nov </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2011/10/'> Oct </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2011/09/'> Sep </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2011/08/'> Aug </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2011/07/'> Jul </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2011/06/'> Jun </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2011/05/'> May </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2011/04/'> Apr </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2011/03/'> Mar </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2011/02/'> Feb </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2011/01/'> Jan </a> </div> <div class='items'> </div> </li> </ul> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class='intervalToggle'> <span class='new-toggle' href='javascript:void(0)'> <i class='material-icons arrow'>  </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'>  </i>   </span> </a> <a class='post-count-link' href='https://blog.chromium.org/2010/'> 2010 </a> </div> <div class='items'> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2010/12/'> Dec </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2010/11/'> Nov </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2010/10/'> Oct </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2010/09/'> Sep </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2010/08/'> Aug </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2010/07/'> Jul </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2010/06/'> Jun </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2010/05/'> May </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2010/04/'> Apr </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2010/03/'> Mar </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2010/02/'> Feb </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2010/01/'> Jan </a> </div> <div class='items'> </div> </li> </ul> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class='intervalToggle'> <span class='new-toggle' href='javascript:void(0)'> <i class='material-icons arrow'>  </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'>  </i>   </span> </a> <a class='post-count-link' href='https://blog.chromium.org/2009/'> 2009 </a> </div> <div class='items'> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2009/12/'> Dec </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2009/11/'> Nov </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2009/09/'> Sep </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2009/08/'> Aug </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2009/07/'> Jul </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2009/06/'> Jun </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2009/05/'> May </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2009/04/'> Apr </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2009/03/'> Mar </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2009/02/'> Feb </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2009/01/'> Jan </a> </div> <div class='items'> </div> </li> </ul> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate expanded'> <div class='intervalToggle'> <span class='new-toggle' href='javascript:void(0)'> <i class='material-icons arrow'>  </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy toggle-open'> <i class='material-icons'>  </i>   </span> </a> <a class='post-count-link' href='https://blog.chromium.org/2008/'> 2008 </a> </div> <div class='items'> <ul class='hierarchy'> <li class='archivedate expanded'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2008/12/'> Dec </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2008/11/'> Nov </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2008/10/'> Oct </a> </div> <div class='items'> </div> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <div class=''> <a class='post-count-link' href='https://blog.chromium.org/2008/09/'> Sep </a> </div> <div class='items'> </div> </li> </ul> </div> </li> </ul> </div> </div> <div class='clear'></div> </div> </div><div class='widget HTML' data-version='1' id='HTML6'> <div class='widget-content'> <a href="http://blog.chromium.org/atom.xml"> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAihJREFUeNrsWa9Pw0AU7viRMDFRBAkzJDMIBIhJJhCzk7NILIqMv4AEhdz+BCY3OYssAlGBoAJREpZwAlHEBO8lr8nSvNeVbu1dyX3JlzTrXfa+u/e9d7c5joWFhYVO1Fa8PwH2gK6m+BRwAvSlAdsrgr8E1jUuMH73GTAEzrkBWymTewZlihhLmgDXIAFuHgGVQOUF7OSYM1p6PgTuA1vAZlUEvAnPdapcMY0VICECekQ0XRfYrqoHsAGNgXfAoMomRiFDEhOZkkL3S88hMaB2LwXp0bj+ps2edpToZpjfoIDQtBeU+xjoDzP2G/gCPKZ5f8WsCAFJoJgOCcFdWSTeL9YQMSvTA1h9BkI5jaiXhLpSCL/8mVZY0UpyJ9ZdOkniu1dmJ96BpzQu9w6s28gcOq9j6pwLdR8/36NK5CQKwJSMrb2MhhSglBpt4UjsrdsnNu0B3J0HCozbCc4TjyY2srEgos/4RQljCzNxl4ireQD8FOq+T+W0mTB2g7njhlR+Sy2jsXFvU658U8YTbeaGpdIu7mWkEAq5ZtIjIhFZdtfX7QHckSvB2B6zC3VdAkZk0kAQwaXTk/CzTXK3wjIExCs6ZJpTnE4uY1KV+KzFzA3KTiFPENHJkOPcsfpLhwe4btoSuvUqAR+6TOxlCE6ZfKUsJLgsqGW8OpqAGx2X+sLxrwUog+JUeQRMDBIwyXOcnlPtPnL0/UsT/8LnOxYWFhZG4leAAQAAQHEaYuzHbAAAAABJRU5ErkJggg==" class="sidebar-icon" /> <h2>Feed</h2> </a> </div> <div class='clear'></div> </div></div> <div class='section' id='sidebar-bottom'><div class='widget HTML' data-version='1' id='HTML4'> <div class='widget-content'> <div class="share followgooglewrapper"> <button data-href="https://twitter.com/intent/follow?original_referer=http://blog.chromium.org/&screen_name=ChromiumDev" onclick='sharingPopup(this);' id='twitter-share'><span class="twitter-follow">Follow @ChromiumDev</span></button> <script> function sharingPopup (button) { var url = button.getAttribute("data-href"); window.open( url,'popUpWindow','height=500,width=500,left=10,top=10,resizable=yes,scrollbars=yes,toolbar=yes,menubar=no,location=no,directories=no,status=yes'); } </script> </div> </div> <div class='clear'></div> </div><div class='widget HTML' data-version='1' id='HTML1'> <div class='widget-content'> Give us feedback in our <a href="http://support.google.com/bin/static.py?hl=en&page=portal_groups.cs">Product Forums</a>. </div> <div class='clear'></div> </div></div> </div> </div> <div style='clear:both;'></div> </div> <!-- Footer --> <div class='google-footer-outer loading'> <div id='google-footer'> <a href='//www.google.com/'> <img class='google-logo-dark' height='36' src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALgAAABICAYAAABFoT/eAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAACLVJREFUeNrsXd+L20YQ3vOprdLqiMXFXE2qB7dcwEcTSB7ykIc+9A/PQx/yEMq1TWhNuYIpJriNr7XpmZ5IxFEvmW2EKs3Ornb1w50PxIFP0kiz387OzM6uhGAwGAxGP3Ho+f7x7ri1O7LdccPqZjSNA4dEHsLfaHcEFedJom93x9Xu2OyOFTcBo6sED3fHZHeMEELrkAHJF0B8Rr+gDFsZ5n0luLTQ95AXs4W06D/tjpR50xtM4CjD0y48YGB4rnyZxNOzyA7zBHr+nLnDaJLg0mo/ALekCasg3Z4XbM0ZdTEgnDPeHY8bIne+Qz2GvwyGNwsuyT218KWvIIBMcwGpLiipcolecjMxfBDchNyS1EvxLiOSIecp31q6IJ/C3yrIrMqMm4jhg+AxkdwbIO3aUO4KjqqMjCT3uaazMBhWBJfuxH3CtRfiXf66DhSRZWbmlMnNaILgZxrXJQO/eO3wORZwvwm4JUxuhheCjzVBYAbW1ces45YDSoZrFNOEE835M8FT6oyeEnws8Fz3QnBxFKPHBMem4GU+m6fPGb0leCTwWcM5B36MPgeZI01gudyDdw3hPeXfo8L/rmCUWnuMMdqUL2WqWeRbhf+twfVsO7YagZGNC79fw7OthEVtkiJ4jJzTd3KPwf3CRqhhiTu23AP5sl0/0xiwISQXpNwLIJK87mHF+U8ddzzdmgKlGzlPYjyxGJQouIhNT4k9AqWEFkqfguIvagTWbcq3KW1WE3xS3m8NtA9WS451xofwjKT5kkDoK/b6mDk5FfXr1lWDL4BofZEv2/SRsK/EHGlGdBdu8QNRb8HMCFwt7Yy3DDI/QP7fx5z3VLhdlJEIs4rKNuXXJXdxZPdB7kfCzWqwCO4V1LHgLjInX3tQ1KzCR52Cz+vDj1dydeRuS74rcvs2Pi6fT5H8OaaUQPQPYcWwRSGXyhhscn5dpAnEFMkuEZetbfkTAnlSuH4DxisE+aMGeJAQ3lFl7C4LJE6QWCaCd583ORQ1jYAwjFctal7nOs2ZZvicwvlZx+RHGrcoAwKUVX8uwcc/9TT65INeDOr5shL9LDRB6QTeIy3zwfdh3WOi6axLCEhSjXU7F3h6LqggUtvyJxpynwu8tDkD98fXApOxRj8zoZ9MnGveYVIVZKaGrkBXCY65BCYNN9NkjpKOyQ81Q79JgdxS+Jn3SDTEXRI7SWzaiSTB32oI3nU3BvMfM0urhOVYgwKhuiAfc4tM07wXwm1ZRoQYSl2NUwiu01fEAHVcpixd745FvVz4dzUUc0o8rwoLy8ZSwU6CyFx1RP5II9+1bFPEFs9HWbNLiimDXE+vCm7u1CS47cofzD3aEhVY57mxRo5zlqdt+RFC1JUH2S7bcVXg4liTMakaBZZVxiTICRoivcn1sEUBlk24JmaC6kxUbYmWoqvyfck2xZGGnDFYa9MMzkYQ1ijkCX6qidybrgePiQ0QIQqoi6qRLeqQfIoRsEHaQJLBdHOnLGetSdm/IPcymJuS1PAnbQPH0MOw/39C1vL11DiLOqIsbDI8QcHvGiLnySi2qUXBicaqUSxN5LEB0g7Jt3ENXJLPJ5S1tnaZBoWbpRqrmjRE7qHmpSmNHdQcYrEUadoh+TbBnc9ri7iycI1kzPeNcLDIvbiqXpez9Tmdq6zGREPuzECBoxrPMiI2WtvyNwhJba2wy3JZ6ky5dD1lSvmZS3e4SPA1wcf1VTFHKX+cGwZzdUYcqpvUtvwrD/InDttVlyZeAKlNN5MKbAiurHhKIPlUuJvlTCCiDjSKSCsUmCFWbGLZwCESfK07JB8LvMYWVtw0D00JEHV8Mq2HkqPbE0oHLvvK2g0o8ETg+4cfwTlZDT9JDoWygu4uQQE/ivIvtcnfPkaCqhiupz7jWOAzqL/vjtcdkv9G4MVMt+EaylfuImiPAXEUjRF3pjjaHiPPZ6If9TGGAO4ZY0am6jOCb+DQ+ZCqLkIpOIPrdNfIjnFPY6nyFut7TS/fanrziOBOKMupKw94WaLMtuVnSFt9CPrWWdJE6PeltCX432DEBoh+5Dv8RRhdis8YAv9uyq4/JAwtlEApgBe9Cw9xDD3tdk4Jn0MDfiHwPHcRPxBePCMER3GuIx7kGlv9fkZ4V9lolx2Uv4X7hEj7qJ3LDoAMGbTRMRibu4L2xQ8bgt8AyU+Q+x7nYrvDnH4iuO5LxKsYwPVbkPMvKF9Zky9wXzRfVWizi62r9X5VHf55h+WHhDjGBZ4WRhyTr6z5SlCoLMxLSpBZFsQ9F80uQFbF/6aFWi+Ev51vzzsuX+msyzuQXXjUz8zEBy+zpq9yweXAoxJW4JbYrDS6gYDqGHxPl+TKeiBfxj9/EBIElPYeOA4y8/qRQfknjvSzgRgtq0Pw/M1eQeMdOSb2Bnrhr6Led+1vcp2x7oTFHMnedFW+Ivlty062BUt74oHgSj+vHepnhunn0JJAMtBZgDI/qmGtMujRv8DDpo47zBJ8UtPOuAR/7rKn8t9AJ0tBdmBAmJ/Fu71yxp4I3qh+DhyRqbi5Y1ShVPlSb8X7bRNcfgZFl+WRGYo7uecrWq1r8X5bhmzP5OdlDwsGRm1suSxkg5rYm7ConyGQ3Zl+DgSD8V/kPwrWBMG9YcBtyShBnTLdTiHgttw7qAW7cqh/ZnmPKr/6ignOaKsdyxbsToT5UkPsW00bJjijDXficcX/JsLs6w2BwGtherdckH3w/kNXRPVI0OqJQoHX42/66IMfMj/2huRjxIidgKV/W0JS+bsstDoTeAHcrI8E5zTh/sDkqxL5rZup55/3USlswfcHf4IrQplVDgW9XFlOqnwr6pVPMMEZTuC60EttvdzbLbaZ4PsFVa3nohhO+vW+yn/ZB2fUhpysmQrzBcTSai9EszuZMcEZ1lCFVrp9zGXhm69iLyY4oxFIa178lPe12I/P2DAYDAaDwWAwGAwGg8FgMBgMBoPBYDD2Cf8IMADDRGoQTe+E9AAAAABJRU5ErkJggg==' style='margin-top: -16px;' width='92'/> </a> <ul> <li> <a href='//www.google.com/'> Google </a> </li> <li> <a href='//www.google.com/policies/privacy/'> Privacy </a> </li> <li> <a href='//www.google.com/policies/terms/'> Terms </a> </li> </ul> </div> </div> <script type='text/javascript'> //<![CDATA[ // Social sharing popups. var postEl = document.getElementsByClassName('social-wrapper'); var postCount = postEl.length; for(i=0; i<postCount;i++){ postEl[i].addEventListener("click", function(event){ var postUrl = this.getAttribute("data-href"); window.open( postUrl,'popUpWindow','height=500,width=500,left=10,top=10,resizable=yes,scrollbars=yes,toolbar=yes,menubar=no,location=no,directories=no,status=yes'); });} //]]> </script> <script type='text/javascript'> //<![CDATA[ var BreakpointHandler = function() { this.initted = false; this.isHomePage = false; this.isMobile = false; }; BreakpointHandler.prototype.finalizeSummary = function(summaryHtml, lastNode) { // Use $.trim for IE8 compatibility summaryHtml = $.trim(summaryHtml).replace(/(<br>|\s)+$/,''); if (lastNode.nodeType == 3) { var lastChar = summaryHtml.slice(-1); if (!lastChar.match(/[.”"?]/)) { if (!lastChar.match(/[A-Za-z]/)) { summaryHtml = summaryHtml.slice(0, -1); } summaryHtml += ' ...'; } } else if (lastNode.nodeType == 1 && (lastNode.nodeName == 'I' || lastNode.nodeName == 'A')) { summaryHtml += ' ...'; } return summaryHtml; }; BreakpointHandler.prototype.generateSummaryFromContent = function(content, numWords) { var seenWords = 0; var summaryHtml = ''; for (var i=0; i < content.childNodes.length; i++) { var node = content.childNodes[i]; var nodeText; if (node.nodeType == 1) { if (node.hasAttribute('data-about-pullquote')) { continue; } nodeText = node.textContent; if (nodeText === undefined) { // innerText for IE8 nodeText = node.innerText; } if (node.nodeName == 'DIV' || node.nodeName == 'B') { // Don't end early if we haven't seen enough words. if (seenWords < 10) { continue; } if (i > 0) { summaryHtml = this.finalizeSummary(summaryHtml, content.childNodes[i-1]); } break; } summaryHtml += node.outerHTML; } else if (node.nodeType == 3) { nodeText = node.nodeValue; summaryHtml += nodeText + ' '; } var words = nodeText.match(/\S+\s*/g); if (!words) { continue; } var remain = numWords - seenWords; if (words.length >= remain) { summaryHtml = this.finalizeSummary(summaryHtml, node); break; } seenWords += words.length; } return summaryHtml; }; BreakpointHandler.prototype.detect = function() { var match, pl = /\+/g, search = /([^&=]+)=?([^&]*)/g, decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); }, query = window.location.search.substring(1); var urlParams = {}; while (match = search.exec(query)) urlParams[decode(match[1])] = decode(match[2]); this.isListPage = $('html').hasClass('list-page'); this.isMobile = urlParams['m'] === '1'; this.isHomePage = window.location.pathname == '/'; }; BreakpointHandler.prototype.initContent = function() { var self = this; $('.post').each(function(index) { var body = $(this).children('.post-body')[0]; var content = $(body).children('.post-content')[0]; $(content).addClass('post-original'); var data = $(content).children('script').html(); data = self.rewriteForSSL(data); // If exists, extract specified editor's preview. var match = data.match(/([\s\S]+?)<div data-is-preview.+?>([\s\S]+)<\/div>/m); if (match) { data = match[1]; } // Prevent big images from loading when they aren't needed. // This must be done as a pre-injection step, since image loading can't be // canceled once embedded into the DOM. if (self.isListPage && self.isMobile) { data = data.replace(/<(img|iframe) .+?>/g, ''); } // Insert template to be rendered as nodes. content.innerHTML = data; if (self.isListPage) { var summary = document.createElement('div'); $(summary).addClass('post-content'); $(summary).addClass('post-summary'); body.insertBefore(summary, content); if (match) { // Use provided summary. summary.innerHTML = match[2]; } else { // Generate a summary. // Summary generation relies on DOM, so it must occur after content is // inserted into the page. summary.innerHTML = self.generateSummaryFromContent(content, 30); } // Add read more link to summary. var titleAnchor = $(this).find('.title a')[0]; var link = titleAnchor.cloneNode(true); link.innerHTML = 'Read More'; $(link).addClass('read-more'); summary.appendChild(link); } }); // Firefox does not allow for proper styling of BR. if (navigator.userAgent.indexOf('Firefox') > -1) { $('.post-content br').replaceWith('<span class="space"></span>'); } $('.loading').removeClass('loading'); }; BreakpointHandler.prototype.process = function() { if (!this.initted) { var makeInsecureImageRegex = function(hosts) { var whitelist = hosts.join('|').replace(/\./g,'\\.'); // Normal image tags, plus input images (yes, this is possible!) return new RegExp('(<(img|input)[^>]+?src=("|\'))http:\/\/(' + whitelist +')', 'g'); }; this.sslImageRegex = makeInsecureImageRegex(BreakpointHandler.KNOWN_HTTPS_HOSTS); this.sslImageCurrentDomainRegex = makeInsecureImageRegex([window.location.hostname]); this.detect(); this.initContent(); this.initted = true; } }; BreakpointHandler.KNOWN_HTTPS_HOSTS = [ "www.google.org", "www.google.com", "services.google.com", "blogger.com", "draft.blogger.com", "www.blogger.com", "photos1.blogger.com", "photos2.blogger.com", "photos3.blogger.com", "blogblog.com", "img1.blogblog.com", "img2.blogblog.com", "www.blogblog.com", "www1.blogblog.com", "www2.blogblog.com", "0.bp.blogspot.com", "1.bp.blogspot.com", "2.bp.blogspot.com", "3.bp.blogspot.com", "4.bp.blogspot.com", "lh3.googleusercontent.com", "lh4.googleusercontent.com", "lh5.googleusercontent.com", "lh6.googleusercontent.com", "themes.googleusercontent.com", ]; BreakpointHandler.prototype.rewriteForSSL = function(html) { // Handle HTTP -> HTTPS source replacement of images, movies, and other embedded content. return html.replace(this.sslImageRegex, '$1https://$4') .replace(this.sslImageCurrentDomainRegex, '$1//$4') .replace(/(<(embed|iframe)[^>]+?src=("|'))http:\/\/([^"']*?(youtube|picasaweb\.google)\.com)/g, '$1https://$4') // Slideshow SWF takes a image host, so we need to rewrite that parameter. .replace(/(<embed[^>]+?feed=http(?=[^s]))/g, '$1s'); }; $(document).ready(function() { var handler = new BreakpointHandler(); handler.process(); // Top-level navigation. $(".BlogArchive .tab").click(function(ev) { ev.preventDefault(); $(this).parent().toggleClass('active'); $(this).siblings().slideToggle(300); }); $(".Label .tab").click(function(ev) { ev.preventDefault(); $(this).parent().toggleClass('active'); $(this).siblings().slideToggle(300); }); // Blog archive year expansion. $('.BlogArchive .intervalToggle').click(function(ev) { ev.preventDefault(); if ($(this).parent().hasClass('collapsed')) { $(this).parent().removeClass('collapsed'); $(this).parent().addClass('expanded'); } else { $(this).parent().removeClass('expanded'); $(this).parent().addClass('collapsed'); } }); // Reverse order of months. $('.BlogArchive .intervalToggle + div').each(function(_, items) { var year = $(this); year.children().each(function(_, month) { year.prepend(month); }); }); // Set anchors to open in new tab. $('.post-content img').parent().each(function(_, node) { if (node.nodeName == 'A') { $(this).attr('target', '_blank'); } }); // Process search requests. $('.searchBox input').on("keypress", function(ev) { if (ev.which == 13) { window.location.href = 'https://www.google.com/search?q=site%3A' + window.location.hostname + '%20' + encodeURIComponent ($(this).val()); } }); }); //]]> </script> <script type="text/javascript" src="https://www.blogger.com/static/v1/widgets/984859869-widgets.js"></script> <script type='text/javascript'> window['__wavt'] = 'AOuZoY6znCla_Z5MQdWJI9gEjAsCXIAONg:1732392529081';_WidgetManager._Init('//www.blogger.com/rearrange?blogID\x3d2471378914199150966','//blog.chromium.org/2008/','2471378914199150966'); _WidgetManager._SetDataContext([{'name': 'blog', 'data': {'blogId': '2471378914199150966', 'title': 'Chromium Blog', 'url': 'https://blog.chromium.org/2008/', 'canonicalUrl': 'https://blog.chromium.org/2008/', 'homepageUrl': 'https://blog.chromium.org/', 'searchUrl': 'https://blog.chromium.org/search', 'canonicalHomepageUrl': 'https://blog.chromium.org/', 'blogspotFaviconUrl': 'https://blog.chromium.org/favicon.ico', 'bloggerUrl': 'https://www.blogger.com', 'hasCustomDomain': true, 'httpsEnabled': true, 'enabledCommentProfileImages': true, 'gPlusViewType': 'FILTERED_POSTMOD', 'adultContent': false, 'analyticsAccountNumber': 'UA-37592578-1', 'encoding': 'UTF-8', 'locale': 'en', 'localeUnderscoreDelimited': 'en', 'languageDirection': 'ltr', 'isPrivate': false, 'isMobile': false, 'isMobileRequest': false, 'mobileClass': '', 'isPrivateBlog': false, 'isDynamicViewsAvailable': true, 'feedLinks': '\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Chromium Blog - Atom\x22 href\x3d\x22https://blog.chromium.org/feeds/posts/default\x22 /\x3e\n\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/rss+xml\x22 title\x3d\x22Chromium Blog - RSS\x22 href\x3d\x22https://blog.chromium.org/feeds/posts/default?alt\x3drss\x22 /\x3e\n\x3clink rel\x3d\x22service.post\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Chromium Blog - Atom\x22 href\x3d\x22https://www.blogger.com/feeds/2471378914199150966/posts/default\x22 /\x3e\n', 'meTag': '', 'adsenseHostId': 'ca-host-pub-1556223355139109', 'adsenseHasAds': false, 'adsenseAutoAds': false, 'boqCommentIframeForm': true, 'loginRedirectParam': '', 'view': '', 'dynamicViewsCommentsSrc': '//www.blogblog.com/dynamicviews/4224c15c4e7c9321/js/comments.js', 'dynamicViewsScriptSrc': '//www.blogblog.com/dynamicviews/d78375fb222d99b3', 'plusOneApiSrc': 'https://apis.google.com/js/platform.js', 'disableGComments': true, 'interstitialAccepted': false, 'sharing': {'platforms': [{'name': 'Get link', 'key': 'link', 'shareMessage': 'Get link', 'target': ''}, {'name': 'Facebook', 'key': 'facebook', 'shareMessage': 'Share to Facebook', 'target': 'facebook'}, {'name': 'BlogThis!', 'key': 'blogThis', 'shareMessage': 'BlogThis!', 'target': 'blog'}, {'name': 'X', 'key': 'twitter', 'shareMessage': 'Share to X', 'target': 'twitter'}, {'name': 'Pinterest', 'key': 'pinterest', 'shareMessage': 'Share to Pinterest', 'target': 'pinterest'}, {'name': 'Email', 'key': 'email', 'shareMessage': 'Email', 'target': 'email'}], 'disableGooglePlus': true, 'googlePlusShareButtonWidth': 0, 'googlePlusBootstrap': '\x3cscript type\x3d\x22text/javascript\x22\x3ewindow.___gcfg \x3d {\x27lang\x27: \x27en\x27};\x3c/script\x3e'}, 'hasCustomJumpLinkMessage': false, 'jumpLinkMessage': 'Read more', 'pageType': 'archive', 'pageName': '2008', 'pageTitle': 'Chromium Blog: 2008'}}, {'name': 'features', 'data': {}}, {'name': 'messages', 'data': {'edit': 'Edit', 'linkCopiedToClipboard': 'Link copied to clipboard!', 'ok': 'Ok', 'postLink': 'Post Link'}}, {'name': 'template', 'data': {'name': 'custom', 'localizedName': 'Custom', 'isResponsive': false, 'isAlternateRendering': false, 'isCustom': true}}, {'name': 'view', 'data': {'classic': {'name': 'classic', 'url': '?view\x3dclassic'}, 'flipcard': {'name': 'flipcard', 'url': '?view\x3dflipcard'}, 'magazine': {'name': 'magazine', 'url': '?view\x3dmagazine'}, 'mosaic': {'name': 'mosaic', 'url': '?view\x3dmosaic'}, 'sidebar': {'name': 'sidebar', 'url': '?view\x3dsidebar'}, 'snapshot': {'name': 'snapshot', 'url': '?view\x3dsnapshot'}, 'timeslide': {'name': 'timeslide', 'url': '?view\x3dtimeslide'}, 'isMobile': false, 'title': 'Chromium Blog', 'description': 'News and developments from the open source browser project', 'url': 'https://blog.chromium.org/2008/', 'type': 'feed', 'isSingleItem': false, 'isMultipleItems': true, 'isError': false, 'isPage': false, 'isPost': false, 'isHomepage': false, 'isArchive': true, 'isLabelSearch': false, 'archive': {'year': 2008, 'rangeMessage': 'Showing posts from 2008'}}}]); _WidgetManager._RegisterWidget('_HeaderView', new _WidgetInfo('Header1', 'header', document.getElementById('Header1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogView', new _WidgetInfo('Blog1', 'main', document.getElementById('Blog1'), {'cmtInteractionsEnabled': false}, 'displayModeFull')); _WidgetManager._RegisterWidget('_HTMLView', new _WidgetInfo('HTML8', 'sidebar-top', document.getElementById('HTML8'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_LabelView', new _WidgetInfo('Label1', 'sidebar', document.getElementById('Label1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogArchiveView', new _WidgetInfo('BlogArchive1', 'sidebar', document.getElementById('BlogArchive1'), {'languageDirection': 'ltr', 'loadingMessage': 'Loading\x26hellip;'}, 'displayModeFull')); _WidgetManager._RegisterWidget('_HTMLView', new _WidgetInfo('HTML6', 'sidebar', document.getElementById('HTML6'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_HTMLView', new _WidgetInfo('HTML4', 'sidebar-bottom', document.getElementById('HTML4'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_HTMLView', new _WidgetInfo('HTML1', 'sidebar-bottom', document.getElementById('HTML1'), {}, 'displayModeFull')); </script> </body> </html>