CINXE.COM

Chromium Blog: 2021

<!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: 2021 </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/2021/' 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/2021/' 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/2021/' 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&amp;zx=3a5e6827-7ceb-4daf-b12c-bebbc55c1d22' media='none' onload='if(media!=&#39;all&#39;)media=&#39;all&#39;' rel='stylesheet'/><noscript><link href='https://www.blogger.com/dyn-css/authorization.css?targetBlogID=2471378914199150966&amp;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='2433316463466189386' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2021/12/chrome-windows-performance-improvements-native-window-occlusion.html' itemprop='url' title='Chrome on Windows performance improvements and the journey of Native Window Occlusion'> Chrome on Windows performance improvements and the journey of Native Window Occlusion </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Thursday, December 9, 2021 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <span id="docs-internal-guid-7fe984ee-7fff-3f35-da76-32a2b7f66d3a"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBnFszV3_OSq9fbqxZvxkYPqk82PcWjLOWM2tdQDkbL8DekbaVTQd-Pm-JqGbly7aHbS5sHAC3BlfoJvKdWtQJjTMu7WTuf0LE2v-H0u0uol7muwJIcSI4YdJUVc2bsn5t9I4fEp_ZuTip/s1999/image2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="830" data-original-width="1999" height="264" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBnFszV3_OSq9fbqxZvxkYPqk82PcWjLOWM2tdQDkbL8DekbaVTQd-Pm-JqGbly7aHbS5sHAC3BlfoJvKdWtQJjTMu7WTuf0LE2v-H0u0uol7muwJIcSI4YdJUVc2bsn5t9I4fEp_ZuTip/w636-h264/image2.jpg" width="636" /></a></div><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><br /><i>Whether you prefer organizing your browser with <a href="https://blog.google/products/chrome/manage-tabs-with-google-chrome/">tab groups</a>, <a href="https://blog.google/products/chrome/more-helpful-chrome-throughout-your-workday/#:~:text=memory%20and%20CPU.-,Name%20your%20windows%C2%A0,-To%20set%20myself">naming your windows</a>, <a href="https://blog.google/products/chrome/faster-chrome/#:~:text=Tabs%3A%20pin%20%E2%80%98em%2C%20group%20%E2%80%98em%2C%20and%20now%20search%20%E2%80%98em">tab search</a>, or another method, you have lots of features that help you get to the tabs you want. In this <a href="https://blog.chromium.org/search/label/the%20fast%20and%20the%20curious">The Fast and the Curious</a> post, we describe how we use what windows are visible to you to optimize Chrome, <b>leading to 25.8% faster start up and 4.5% fewer crashes.</b></i></span><div><span><i><br /></i></span></div><div><i><br /></i><h1 style="text-align: left;"><span>Background</span></h1>For several years, to improve the user experience, Chrome has lowered the priority of background tabs<span style="font-size: xx-small;">[1]</span>. For example, JavaScript is throttled in background tabs, and these tabs don&#8217;t <a href="https://www.chromium.org/developers/design-documents/multi-process-architecture">render </a>web content. This reduces CPU, GPU and memory usage, which leaves more memory, CPU and GPU for foreground tabs that the user actually sees. However, the logic was limited to tabs that weren't focused in their window, or windows that were minimized or otherwise moved offscreen.<br /><br />Through experiments, we found that nearly 20% of Chrome windows are completely covered by other windows, i.e., occluded. If these occluded windows were treated like background tabs, our hypothesis was that we would see significant performance benefits. So, around three years ago, we started working on a project to track the occlusion state of each Chrome window in real time, and lower the priority of tabs in occluded windows. We called this project Native Window Occlusion, because we had to know about the location of native, non-Chrome windows on the user&#8217;s screen. (The location information is discarded immediately after it is used in the occlusion calculation.)</div><div><span><br /></span><h1 style="text-align: left;"><span>Calculating Native Window Occlusion</span></h1><span>The Windows OS doesn&#8217;t provide a direct way to find out if a window is completely covered by other windows, so Chrome has to figure it out on its own. If we only had to worry about other Chrome windows, this would be simple because we know where Chrome windows are, but we have to consider all the non-Chrome windows a user might have open, and know about anything that happens that might change whether Chrome windows are occluded or not.<br /><br />There are two main pieces to keeping track of which Chrome windows are occluded. The first is the occlusion calculation, which consists of iterating over the open windows on the desktop, in<a href="https://en.wikipedia.org/wiki/Z-order"> z-order</a> (front to back) and seeing if the windows in front of a Chrome window completely cover it. The second piece is deciding when to do the occlusion calculation.</span></div><div><span><br /></span><h1 style="text-align: left;"><span>Calculating Occlusion</span></h1><span>In theory, figuring out which windows are occluded is fairly simple. In practice, however, there are lots of complications, such as <a href="https://docs.microsoft.com/en-us/windows/win32/gdi/multiple-monitor-system-metrics">multi-monitor setups</a>, <a href="https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nn-shobjidl_core-ivirtualdesktopmanager">virtual desktops</a>, <a href="https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getlayeredwindowattributes">non-opaque windows</a>, and even <a href="https://docs.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute">cloaked windows</a>(!). This needs to be done with great care, because if we decide that a window is occluded when in fact it is visible to the user, then the area where the user expects to see web contents will be white. We also don&#8217;t want to block the UI thread while doing the occlusion calculation, because that could reduce the responsiveness of Chrome and degrade the user experience. So, we compute occlusion on a separate thread, as follows:<br /><ol style="text-align: left;"><li><span>Ignore minimized windows, since they&#8217;re not visible.</span></li><li><span>Mark Chrome windows on a different virtual desktop as occluded.</span></li><li><span>Compute the virtual screen rectangle, which combines the display monitors. This is the unoccluded screen rectangle.</span></li><li>Iterate over the open windows on the desktop from front to back, ignoring invisible windows, transparent windows, floating windows (windows with style <a href="https://docs.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles">WS_EX_TOOLBAR</a>), cloaked windows, windows on other virtual desktops, non-rectangular windows<span style="font-size: xx-small;">[2]</span>, etc. Ignoring these kinds of windows may cause some occluded windows to be considered visible (false negatives) but importantly it won&#8217;t lead to treating visible windows as occluded (false positives). For each window:</li><ul><li><span>Subtract the window's area from the unoccluded screen rectangle.</span></li><li><span>If the window is a Chrome window, check if its area overlapped with the unoccluded area. If it didn&#8217;t, that means the Chrome window is completely covered by previous windows, so it is occluded.</span></li></ul><li><span>Keep iterating until all Chrome windows are captured.</span></li><li>At this point, any Chrome window that we haven&#8217;t marked occluded is visible, and we&#8217;re done computing occlusion. Whew! Now we post a task to the UI thread to update the visibility of the Chrome windows.</li><li>This is all done without synchronization locks, so the occlusion calculation has minimal effect on the UI thread, e.g., it will not ever block the UI thread and degrade the user experience.</li></ol>For more detailed implementation information, see the <a href="https://source.chromium.org/chromium/chromium/src/+/main:docs/windows_native_window_occlusion_tracking.md">documentation</a>.</span></div><div><span><br /></span></div><div><br /><h1 style="text-align: left;"><span>Deciding When to Calculate Occlusion</span></h1>We don&#8217;t want to continuously calculate occlusion because it would degrade the performance of Chrome, so we need to know when a window might become visible or occluded. Fortunately, Windows lets you track various system events, like windows moving or getting resized/maximized/minimized. The occlusion-calculation thread tells Windows that it wants to track those events, and when notified of an event, it examines the event to decide whether to do a new occlusion calculation. Because we may get several events in a very short time, we don&#8217;t calculate occlusion more than once every 16 milliseconds, which corresponds to the time a single frame is displayed, assuming a frame rate of 60 frames per second (fps).<br /><br />Some of the events we listen for are windows getting activated or deactivated, windows moving or resizing, the user locking or unlocking the screen, turning off the monitor, etc. We don&#8217;t want to calculate occlusion more than necessary, but we don&#8217;t want to miss an event that causes a window to become visible, because if we do, the user will see a white area where their web contents should be. It&#8217;s a delicate balance<span style="font-size: xx-small;">[3]</span>.<br /><br />The events we listen for are focused on whether a Chrome window is occluded. For example, moving the mouse generates a lot of events, and cursors generate an event for every blink, so we ignore events that aren&#8217;t for window objects. We also ignore events for most popup windows, so that tooltips getting shown doesn&#8217;t trigger an occlusion calculation.<br /><br />The occlusion thread tells Windows that it wants to know about various Windows events. The UI thread tells Windows that it wants to know when there are major state changes, e.g., the monitor is powered off, or the user locks the screen.<br /><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwrZ4rNITxC_LTgirCCPJ-nPrAEMEIz4_LAHTWRI7ZDKj3aFjb-QnnIzihx3W6-GNRkF6nnw1OHxF9bJ8u9b0mzrfA-dahpyY4QrI1LfFeibQXcZLlzrBNkqAW6fChQAEAaHIk1elJTMOj/s1999/image1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="1328" data-original-width="1999" height="404" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwrZ4rNITxC_LTgirCCPJ-nPrAEMEIz4_LAHTWRI7ZDKj3aFjb-QnnIzihx3W6-GNRkF6nnw1OHxF9bJ8u9b0mzrfA-dahpyY4QrI1LfFeibQXcZLlzrBNkqAW6fChQAEAaHIk1elJTMOj/w607-h404/image1.png" width="607" /></a><br /> <br /><br /><h1 style="text-align: left;"><span>Results</span></h1>This feature was developed behind an <a href="https://www.chromium.org/developers/design-documents/experiments">experiment</a> to measure its effect and rolled out to 100% of Chrome Windows users in October 2020 as part of the M86 release. Our metrics show significant performance benefits with the feature turned on:<br /><ul style="text-align: left;"><li><span>8.5% to 25.8% faster startup</span></li><li><span>3.1% reduction in GPU memory usage</span></li><li><span>20.4% fewer renderer frames drawn overall</span></li><li><span>4.5% fewer clients experiencing renderer crashes</span></li><li><span>3.0% improvement in <a href="https://web.dev/fid/">first input delay</a></span></li><li><span>6.7% improvement in <a href="https://web.dev/fcp/">first contentful paint</a> and <a href="https://web.dev/lcp/">largest contentful paint</a></span></li></ul>A reason for the startup and first-contentful-paint improvements is when Chrome restores two or more full-screen windows when starting up, one of the windows is likely to be occluded. Chrome will now skip much of the work for that window, thus saving resources for the more important foreground window.<br /><br />Posted by David Bienvenu, Chrome Developer<br /><br /><i>Data source for all statistics: <a href="https://www.google.com/chrome/privacy/whitepaper.html#usagestats">Real-world data</a> anonymously aggregated from Chrome clients.</i></div><div><span><i>[1] Note that certain tabs are exempt from having their priority lowered, e.g., tabs playing audio or video.</i></span></div><div><span><i>[2] Non-rectangular windows complicate the calculations and were thought to be rare, but it turns out non-rectangular windows are common on Windows 7, due to some quirks of the default Windows 7 theme.</i></span></div><div><i>[3] When this was initially launched, we quickly discovered that Citrix users were getting white windows whenever another user locked their screen, due to Windows sending us session changed notifications for sessions that were not the current session. For the details, look <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=1024837">here</a>.</i></div> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <span id="docs-internal-guid-7fe984ee-7fff-3f35-da76-32a2b7f66d3a"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBnFszV3_OSq9fbqxZvxkYPqk82PcWjLOWM2tdQDkbL8DekbaVTQd-Pm-JqGbly7aHbS5sHAC3BlfoJvKdWtQJjTMu7WTuf0LE2v-H0u0uol7muwJIcSI4YdJUVc2bsn5t9I4fEp_ZuTip/s1999/image2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="830" data-original-width="1999" height="264" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBnFszV3_OSq9fbqxZvxkYPqk82PcWjLOWM2tdQDkbL8DekbaVTQd-Pm-JqGbly7aHbS5sHAC3BlfoJvKdWtQJjTMu7WTuf0LE2v-H0u0uol7muwJIcSI4YdJUVc2bsn5t9I4fEp_ZuTip/w636-h264/image2.jpg" width="636" /></a></div><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><br /><i>Whether you prefer organizing your browser with <a href="https://blog.google/products/chrome/manage-tabs-with-google-chrome/">tab groups</a>, <a href="https://blog.google/products/chrome/more-helpful-chrome-throughout-your-workday/#:~:text=memory%20and%20CPU.-,Name%20your%20windows%C2%A0,-To%20set%20myself">naming your windows</a>, <a href="https://blog.google/products/chrome/faster-chrome/#:~:text=Tabs%3A%20pin%20%E2%80%98em%2C%20group%20%E2%80%98em%2C%20and%20now%20search%20%E2%80%98em">tab search</a>, or another method, you have lots of features that help you get to the tabs you want. In this <a href="https://blog.chromium.org/search/label/the%20fast%20and%20the%20curious">The Fast and the Curious</a> post, we describe how we use what windows are visible to you to optimize Chrome, <b>leading to 25.8% faster start up and 4.5% fewer crashes.</b></i></span><div><span><i><br /></i></span></div><div><i><br /></i><h1 style="text-align: left;"><span>Background</span></h1>For several years, to improve the user experience, Chrome has lowered the priority of background tabs<span style="font-size: xx-small;">[1]</span>. For example, JavaScript is throttled in background tabs, and these tabs don&#8217;t <a href="https://www.chromium.org/developers/design-documents/multi-process-architecture">render </a>web content. This reduces CPU, GPU and memory usage, which leaves more memory, CPU and GPU for foreground tabs that the user actually sees. However, the logic was limited to tabs that weren't focused in their window, or windows that were minimized or otherwise moved offscreen.<br /><br />Through experiments, we found that nearly 20% of Chrome windows are completely covered by other windows, i.e., occluded. If these occluded windows were treated like background tabs, our hypothesis was that we would see significant performance benefits. So, around three years ago, we started working on a project to track the occlusion state of each Chrome window in real time, and lower the priority of tabs in occluded windows. We called this project Native Window Occlusion, because we had to know about the location of native, non-Chrome windows on the user&#8217;s screen. (The location information is discarded immediately after it is used in the occlusion calculation.)</div><div><span><br /></span><h1 style="text-align: left;"><span>Calculating Native Window Occlusion</span></h1><span>The Windows OS doesn&#8217;t provide a direct way to find out if a window is completely covered by other windows, so Chrome has to figure it out on its own. If we only had to worry about other Chrome windows, this would be simple because we know where Chrome windows are, but we have to consider all the non-Chrome windows a user might have open, and know about anything that happens that might change whether Chrome windows are occluded or not.<br /><br />There are two main pieces to keeping track of which Chrome windows are occluded. The first is the occlusion calculation, which consists of iterating over the open windows on the desktop, in<a href="https://en.wikipedia.org/wiki/Z-order"> z-order</a> (front to back) and seeing if the windows in front of a Chrome window completely cover it. The second piece is deciding when to do the occlusion calculation.</span></div><div><span><br /></span><h1 style="text-align: left;"><span>Calculating Occlusion</span></h1><span>In theory, figuring out which windows are occluded is fairly simple. In practice, however, there are lots of complications, such as <a href="https://docs.microsoft.com/en-us/windows/win32/gdi/multiple-monitor-system-metrics">multi-monitor setups</a>, <a href="https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nn-shobjidl_core-ivirtualdesktopmanager">virtual desktops</a>, <a href="https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getlayeredwindowattributes">non-opaque windows</a>, and even <a href="https://docs.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute">cloaked windows</a>(!). This needs to be done with great care, because if we decide that a window is occluded when in fact it is visible to the user, then the area where the user expects to see web contents will be white. We also don&#8217;t want to block the UI thread while doing the occlusion calculation, because that could reduce the responsiveness of Chrome and degrade the user experience. So, we compute occlusion on a separate thread, as follows:<br /><ol style="text-align: left;"><li><span>Ignore minimized windows, since they&#8217;re not visible.</span></li><li><span>Mark Chrome windows on a different virtual desktop as occluded.</span></li><li><span>Compute the virtual screen rectangle, which combines the display monitors. This is the unoccluded screen rectangle.</span></li><li>Iterate over the open windows on the desktop from front to back, ignoring invisible windows, transparent windows, floating windows (windows with style <a href="https://docs.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles">WS_EX_TOOLBAR</a>), cloaked windows, windows on other virtual desktops, non-rectangular windows<span style="font-size: xx-small;">[2]</span>, etc. Ignoring these kinds of windows may cause some occluded windows to be considered visible (false negatives) but importantly it won&#8217;t lead to treating visible windows as occluded (false positives). For each window:</li><ul><li><span>Subtract the window's area from the unoccluded screen rectangle.</span></li><li><span>If the window is a Chrome window, check if its area overlapped with the unoccluded area. If it didn&#8217;t, that means the Chrome window is completely covered by previous windows, so it is occluded.</span></li></ul><li><span>Keep iterating until all Chrome windows are captured.</span></li><li>At this point, any Chrome window that we haven&#8217;t marked occluded is visible, and we&#8217;re done computing occlusion. Whew! Now we post a task to the UI thread to update the visibility of the Chrome windows.</li><li>This is all done without synchronization locks, so the occlusion calculation has minimal effect on the UI thread, e.g., it will not ever block the UI thread and degrade the user experience.</li></ol>For more detailed implementation information, see the <a href="https://source.chromium.org/chromium/chromium/src/+/main:docs/windows_native_window_occlusion_tracking.md">documentation</a>.</span></div><div><span><br /></span></div><div><br /><h1 style="text-align: left;"><span>Deciding When to Calculate Occlusion</span></h1>We don&#8217;t want to continuously calculate occlusion because it would degrade the performance of Chrome, so we need to know when a window might become visible or occluded. Fortunately, Windows lets you track various system events, like windows moving or getting resized/maximized/minimized. The occlusion-calculation thread tells Windows that it wants to track those events, and when notified of an event, it examines the event to decide whether to do a new occlusion calculation. Because we may get several events in a very short time, we don&#8217;t calculate occlusion more than once every 16 milliseconds, which corresponds to the time a single frame is displayed, assuming a frame rate of 60 frames per second (fps).<br /><br />Some of the events we listen for are windows getting activated or deactivated, windows moving or resizing, the user locking or unlocking the screen, turning off the monitor, etc. We don&#8217;t want to calculate occlusion more than necessary, but we don&#8217;t want to miss an event that causes a window to become visible, because if we do, the user will see a white area where their web contents should be. It&#8217;s a delicate balance<span style="font-size: xx-small;">[3]</span>.<br /><br />The events we listen for are focused on whether a Chrome window is occluded. For example, moving the mouse generates a lot of events, and cursors generate an event for every blink, so we ignore events that aren&#8217;t for window objects. We also ignore events for most popup windows, so that tooltips getting shown doesn&#8217;t trigger an occlusion calculation.<br /><br />The occlusion thread tells Windows that it wants to know about various Windows events. The UI thread tells Windows that it wants to know when there are major state changes, e.g., the monitor is powered off, or the user locks the screen.<br /><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwrZ4rNITxC_LTgirCCPJ-nPrAEMEIz4_LAHTWRI7ZDKj3aFjb-QnnIzihx3W6-GNRkF6nnw1OHxF9bJ8u9b0mzrfA-dahpyY4QrI1LfFeibQXcZLlzrBNkqAW6fChQAEAaHIk1elJTMOj/s1999/image1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="1328" data-original-width="1999" height="404" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwrZ4rNITxC_LTgirCCPJ-nPrAEMEIz4_LAHTWRI7ZDKj3aFjb-QnnIzihx3W6-GNRkF6nnw1OHxF9bJ8u9b0mzrfA-dahpyY4QrI1LfFeibQXcZLlzrBNkqAW6fChQAEAaHIk1elJTMOj/w607-h404/image1.png" width="607" /></a><br /> <br /><br /><h1 style="text-align: left;"><span>Results</span></h1>This feature was developed behind an <a href="https://www.chromium.org/developers/design-documents/experiments">experiment</a> to measure its effect and rolled out to 100% of Chrome Windows users in October 2020 as part of the M86 release. Our metrics show significant performance benefits with the feature turned on:<br /><ul style="text-align: left;"><li><span>8.5% to 25.8% faster startup</span></li><li><span>3.1% reduction in GPU memory usage</span></li><li><span>20.4% fewer renderer frames drawn overall</span></li><li><span>4.5% fewer clients experiencing renderer crashes</span></li><li><span>3.0% improvement in <a href="https://web.dev/fid/">first input delay</a></span></li><li><span>6.7% improvement in <a href="https://web.dev/fcp/">first contentful paint</a> and <a href="https://web.dev/lcp/">largest contentful paint</a></span></li></ul>A reason for the startup and first-contentful-paint improvements is when Chrome restores two or more full-screen windows when starting up, one of the windows is likely to be occluded. Chrome will now skip much of the work for that window, thus saving resources for the more important foreground window.<br /><br />Posted by David Bienvenu, Chrome Developer<br /><br /><i>Data source for all statistics: <a href="https://www.google.com/chrome/privacy/whitepaper.html#usagestats">Real-world data</a> anonymously aggregated from Chrome clients.</i></div><div><span><i>[1] Note that certain tabs are exempt from having their priority lowered, e.g., tabs playing audio or video.</i></span></div><div><span><i>[2] Non-rectangular windows complicate the calculations and were thought to be rare, but it turns out non-rectangular windows are common on Windows 7, due to some quirks of the default Windows 7 theme.</i></span></div><div><i>[3] When this was initially launched, we quickly discovered that Citrix users were getting white windows whenever another user locked their screen, due to Windows sending us session changed notifications for sessions that were not the current session. For the details, look <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=1024837">here</a>.</i></div> <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 on Windows performance improvements and the journey of Native Window Occlusion&url=https://blog.chromium.org/2021/12/chrome-windows-performance-improvements-native-window-occlusion.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/2021/12/chrome-windows-performance-improvements-native-window-occlusion.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/2021/12/chrome-windows-performance-improvements-native-window-occlusion.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> <span class='labels-caption'> Labels: </span> <span class='labels'> <a class='label' href='https://blog.chromium.org/search/label/performance' rel='tag'> performance </a> , <a class='label' href='https://blog.chromium.org/search/label/the%20fast%20and%20the%20curious' rel='tag'> the fast and the curious </a> </span> </div> </div> </div> <div class='post' data-id='9207931682847107271' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2021/12/faster-chrome-let-the-compiler-do-the-work.html' itemprop='url' title='Faster Chrome - Let The Compiler do the work'> Faster Chrome - Let The Compiler do the work </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Wednesday, December 1, 2021 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTMoYEIdhyB0zEy13cEqUkDosQm9WTI6b2uOlS2-FwwfovfDeub91dbJzjB7sVqp8JvRptqT032o0hywAGouB6SoELn9Zo6z8dRoT2_hWx-qYiTydYtltYbQt_sf2b206JRfIgAEm0xdNV/s1999/image1.jpg" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="830" data-original-width="1999" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTMoYEIdhyB0zEy13cEqUkDosQm9WTI6b2uOlS2-FwwfovfDeub91dbJzjB7sVqp8JvRptqT032o0hywAGouB6SoELn9Zo6z8dRoT2_hWx-qYiTydYtltYbQt_sf2b206JRfIgAEm0xdNV/w578-h240/image1.jpg" width="578" /></a><br /><br /><i>Chrome is fast, but there's always room for improvement. Often, that's achieved by carefully crafting the algorithms that make up Chrome. But there's a lot of Chrome, so why not let computers do at least some part of our work? In this installment of <a href="https://blog.chromium.org/search/label/the%20fast%20and%20the%20curious">The Fast And the Curious</a>, we'll show you several changes in how we build Chrome to achieve a <b>25.8% higher score on Speedometer on Windows and a 22.0% increase in browser responsiveness. </b><br /></i><br /><br /><div><h1 style="text-align: left;">Why speed?</h1>So why do we care about performance benchmarks? It's not a simple "higher numbers is better" chasing of achievements - performance was so important to Chrome that we embedded in our <a href="https://www.chromium.org/developers/core-principles">core principles</a>, the "4Ss" - Speed, Security, Stability, Simplicity. And speed matters because we want a browser that responds quickly. Speed matters so much because we want to build a faster and more responsive browser. And by improving the speed of the browser, there's the additional benefit of maximizing battery use, so you don't have to charge your laptop/devices as often.<br /><br /><br /><h1 style="text-align: left;">Speed? Size? Something Else?</h1>Let's look at a typical optimization.<br /><br /><br /></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div><span style="font-family: courier;"><span style="color: #2b00fe;">int</span> foo();</span></div><div><span style="font-family: courier;"><span style="color: #2b00fe;">int</span> fiver(<span style="color: #2b00fe;">int</span> num) {</span></div><div><span style="color: #2b00fe; font-family: courier;">&nbsp; for</span><span style="font-family: courier;">(</span><span style="color: #2b00fe; font-family: courier;">int</span><span style="font-family: courier;"> j = </span><span style="color: #38761d; font-family: courier;">0</span><span style="font-family: courier;">; j &lt; </span><span style="color: #38761d; font-family: courier;">5</span><span style="font-family: courier;">; j++)</span></div><div><span style="font-family: courier;">&nbsp; &nbsp; num = num + foo();</span></div><div><span style="font-family: courier;"><span style="color: #2b00fe;"> return</span> num;</span></div><div><span style="font-family: courier;">}</span></div></blockquote><div><br /><br />The compiler can either compile this as a loop (<a href="https://godbolt.org/z/ja7d6x7hE">smaller</a>), or turn it into five additions in a row (<a href="https://godbolt.org/z/x76PohPz9">faster, but bigger</a>)<br /><br />You save the cost of checking the end of the loop and incrementing a variable every time through the loop. But in exchange, you now have many repeated calls to foo(). If foo() is called a lot, that is a lot of space.<br /><br />And while speed matters a lot, we also care about binary size. (Yes, we see your memes!) And that tradeoff - exchanging speed for memory, and vice versa, holds for a lot of compiler optimizations.<br /><br />So how do you decide if the cost is worth it? One good way is to optimize for speed in areas that are run often, because your speed wins accumulate each time you run a function. You could just guess at what you inline (your compiler can do this, it's called "a heuristic", it's an educated guess), and then measure speed and code size.<br /><br />The result: Likely faster. Likely larger. Is that good?<br /><br />Ask any engineer a question like that, and they will answer &#8220;It depends&#8221;. So, how do you get an answer?<br /><br /><br /><h1 style="text-align: left;">The More You Know&#8230; (profiling &amp; PGO)</h1>The best way to make a decision is with data. We collect data based on what gets run a lot, and what gets run a little. We do that for several different scenarios, because our users do lots of different things with Chrome and want them to be fast.<br /><br />Our goal is collecting performance data in various scenarios, and using that to guide the compiler. There are 3 steps needed:<br /><ol style="text-align: left;"><li>Instrument for profiling</li><li>Run that instrumented executable in various scenarios</li><li>Use the resulting performance profile to guide the compiler. </li></ol><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8UX1Gvrp7O9Z9l6q7atdjs1E8XhJ4nWxlLZboPoann09dFmi9NVimkKdN_3nyMCyhOXylL70s2ip_BsgrkIhzseLa7vIK52NVFAdol5SWeASSrfG0NYL6KhugX5C4wXI0gnHx9nBkpm9l/s1999/image2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1328" data-original-width="1999" height="365" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8UX1Gvrp7O9Z9l6q7atdjs1E8XhJ4nWxlLZboPoann09dFmi9NVimkKdN_3nyMCyhOXylL70s2ip_BsgrkIhzseLa7vIK52NVFAdol5SWeASSrfG0NYL6KhugX5C4wXI0gnHx9nBkpm9l/w548-h365/image2.png" width="548" /></a></div><br /><div><br /></div><h1 style="text-align: left;">But we can do more (ThinLTO)</h1>That's a good start, but we can do better. Let's look at inlining - the compiler takes the code of a called function and inserts all of it at the callsite.<br /> <br /><br /></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div><span style="font-family: courier;"><span style="color: #2b00fe;">inline</span> int foo() { <span style="color: #2b00fe;">return</span> <span style="color: #38761d;">3</span>; };</span></div><div><span style="font-family: courier;"><span style="color: #2b00fe;">int</span> fiver_inline(<span style="color: #2b00fe;">int</span> num) {</span></div><div><span style="font-family: courier;">&nbsp; <span style="color: #2b00fe;">for</span>(<span style="color: #2b00fe;">int</span> j = <span style="color: #38761d;">0</span>; j &lt; <span style="color: #38761d;">5</span>; j++)</span></div><div><span style="font-family: courier;">&nbsp; &nbsp; num = num + foo();</span></div><div><span style="font-family: courier;"><span style="color: #2b00fe;"> return</span> num;</span></div><div><span style="font-family: courier;">}</span></div></blockquote><div><br /><br />When the compiler inlines foo(), it turns into<br /><br /></div><div><br /></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div><span style="font-family: courier;"><span style="color: #2b00fe;">int</span> fiver_inline(<span style="color: #2b00fe;">int</span> num) {</span></div><div><span style="font-family: courier;"><span style="color: #2b00fe;">&nbsp; for</span>(int j = <span style="color: #38761d;">0</span>; j &lt; <span style="color: #38761d;">5</span>; j++)</span></div><div><span style="font-family: courier;">&nbsp; &nbsp; num = num + 3;</span></div><div><span style="font-family: courier;"><span style="color: #2b00fe;"> return</span> num;</span></div><div><span style="font-family: courier;">}</span></div></blockquote><div><br /><br />Not bad - saves us the function call and all the setup that goes with having a function. But the compiler can in fact even do better - because now all the information is in one place. The compiler can apply that knowledge and deduce that fiver_inline() adds the number three and does so 5 times - and so the entire code is <a href="https://godbolt.org/z/dY1vGPYbj">boiled down to</a><br /> <br /><br /></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px;"><div style="text-align: left;"><span style="font-family: courier;"> return num + 15;</span></div></blockquote><div><br /><br />Which is awesome! But the compiler can only do this if the source code for foo() and the location where it is called are in the same source file - otherwise, the compiler does not know what to inline. (That's the fiver() example). A trivial way around that is to combine all the source files into one giant source file and compile and link that in one go.<br /><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8BzcLrQhHkvTNWkCVVYvXvGRC_a3s8XQ5WiLaUvbQZ6ipn_dafovEHOsIVPVw-E4BqniRWroaVW-02S38rYaLjyDNbrduQfOUF4tDvQIrdLe4q1-4uF8dbBHVtGc4DWXvSMawVRjAIYNz/s1999/image4.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="1329" data-original-width="1999" height="384" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8BzcLrQhHkvTNWkCVVYvXvGRC_a3s8XQ5WiLaUvbQZ6ipn_dafovEHOsIVPVw-E4BqniRWroaVW-02S38rYaLjyDNbrduQfOUF4tDvQIrdLe4q1-4uF8dbBHVtGc4DWXvSMawVRjAIYNz/w577-h384/image4.png" width="577" /></a><br /><br /><br />There's just one downside - that approach needs to generate all of the machine code for Chrome, all the time. Change one line in one file, compile all of Chrome. And there's a lot of Chrome. It also effectively disables caching build results and so makes remote compilation much less useful. (And we rely a lot on remote compilation &amp; caching so we can quickly build new versions of Chrome.)<br /><br />So, back to the drawing board. The core insight is that each source file only needs to include a few functions - it doesn't need to see every single other file. All that's needed is "cleverly" mixing the right inline functions into the right source files. <br /><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIt3Ouc89cdmpjZsdj3zaVYfBr5fjS3VYwqkW2QORzF3vhll3kDLAdvYIE_vovOWUjDwHr7DXt3UpKLesNGxBD3CszjSbf4xgDRk-AzMgMq7lTrlIIXY6rpgXx9p17Ws5aoMYEWZO5k5p4/s1999/image3.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="1329" data-original-width="1999" height="405" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIt3Ouc89cdmpjZsdj3zaVYfBr5fjS3VYwqkW2QORzF3vhll3kDLAdvYIE_vovOWUjDwHr7DXt3UpKLesNGxBD3CszjSbf4xgDRk-AzMgMq7lTrlIIXY6rpgXx9p17Ws5aoMYEWZO5k5p4/w608-h405/image3.png" width="608" /></a><br /><br /><br />Now we're back to compiling individual source files. Distributed/cached compilation works again, small changes don't cause a full rebuild, and since "ThinLTO" does just inline a few functions, and it is relatively little overhead.<br /><br />Of course, the question of "which functions should ThinLTO inline?" still needs to be answered. And the answer is still "the ones that are small and called a lot". Hey, we know those already - from the profiles we generated for Profile Guided Optimization (PGO). Talk about lucky coincidences!<br /><br /><br /><h1 style="text-align: left;">But wait, there's more! (Callgraph Sorting)</h1>We've done a lot for inlined function calls. Is there anything we can do to speed up functions that haven't been inlined, too? Turns out there is. <br /><br />One important factor is that the CPU doesn't fetch data byte by byte, but in chunks. And so, if we could ensure that a chunk of data doesn't just contain the function we need right now, but ideally also the ones that we'll need next, we could ensure that we have to go out and get chunks of data less often.<br /><br />In other words, we want functions that are called right after the other to live next to each other in memory also ("code locality"). And we already know which functions are called close to each other - because we ran our profiling and stored performance profiles for PGO.<br /><br />We can then use that information to ensure that the right functions are next to each other when we link.<br /><br /><br />I.e.<br /><br /><br /></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div><span style="font-family: courier;">g.c</span></div><div><span style="font-family: courier;">&nbsp; extern int f1();</span></div><div><span style="font-family: courier;">&nbsp; extern int f2();</span></div><div><span style="font-family: courier;">&nbsp; extern int f3();</span></div><div><span style="font-family: courier;">&nbsp; int g() {</span></div><div><span style="font-family: courier;">&nbsp; &nbsp; f1();</span></div><div><span style="font-family: courier;">&nbsp; &nbsp; for(..) {</span></div><div><span style="font-family: courier;">&nbsp; &nbsp; &nbsp; f3();</span></div><div><span style="font-family: courier;">&nbsp; }</span></div><div><span style="font-family: courier;">&nbsp; f1();</span></div><div><span style="font-family: courier;">&nbsp; f2();</span></div><div><span style="font-family: courier;">}</span></div></blockquote><div><br /><br />could be interpreted as "g() calls f3() a lot - so keep that one really close. f1() is called twice, so&#8230; somewhat close. And if we can squeeze in f2, even better". The calling sequence is a "call graph", and so this sorting process is called "call graph sorting".<br /><br />Just changing the order of functions in memory might not sound like a lot, but it leads to <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=1113282">~3% performance improvement</a>. And to know which functions calls which other ones a lot&#8230; yep. You guessed it. Our profiles from the PGO work pay off again.<br /><br /><br /><h1 style="text-align: left;">One more thing.</h1>It turns out that the compiler can make even more use of that profile data for PGO. (Not a surprise - once you know where the slow spots are, exactly, you can do a lot to improve!). To make use of that, and enable further improvements, LLVM has something called the "new pass manager". In a nutshell, it's a new way to run optimizations within LLVM, and it helps a lot with PGO. For much more detail, I'd suggest reading the <a href="https://blog.llvm.org/posts/2021-03-26-the-new-pass-manager/">LLVM blog post</a>. <br /><br />Turning that on leads to another ~3% performance increase, and ~9MB size reduction.<br /><br /></div><div><br /></div><div><h1 style="text-align: left;">Why Now?</h1>Good question. One part of that is that PGO &amp; profiling unlock an entire new set of optimizations, as you've seen above. It makes sense to do that all in one go. <br /><br />The other reason is our toolchain. We used to have a colorful mix of different technologies for compilers and linkers on different platforms.<br /><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFfNBpFNKtZU6og2qYYDDCMy-zyUx3BfEM1JtiTghtW28hCZgL8MZ3Hm-lTCyTvM-9rlUTsrKvQjPHvIzLmivvfPyjukj4a72vDkcwP2Dj5kGCwCr1cjQt1Vt79LladQN140itD6tavWMj/s916/9NcAMNnoAe52Ly9.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="319" data-original-width="916" height="166" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFfNBpFNKtZU6og2qYYDDCMy-zyUx3BfEM1JtiTghtW28hCZgL8MZ3Hm-lTCyTvM-9rlUTsrKvQjPHvIzLmivvfPyjukj4a72vDkcwP2Dj5kGCwCr1cjQt1Vt79LladQN140itD6tavWMj/w478-h166/9NcAMNnoAe52Ly9.png" width="478" /></a><br /><br /><br />And since this work requires changes to compilers and linkers, that would mean changing the build - and testing it - across 5 compilers and 4 linkers. But, thankfully, we've simplified our toolchain (Simplicity - another one of the 4S's!). To be able to do this, we worked with the LLVM community to make clang a great <a href="https://blog.llvm.org/2018/03/clang-is-now-used-to-build-chrome-for.html">Windows compiler</a>, in addition to partnering with the LLVM community to create new ELF (Linux), COFF (Windows), and Mach-O (macOS, iOS) linkers.<br /><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiif6su4dE04GQyDm7D6oXewenzOOb-2vHpA0asi8HUFB0F1rkXYna3j0tsEX0Z-iGzQoGI5p0Qm4Sk2oPGvgr_zwII8TY9HS6hWK6TxS_0ODeTjvfeOsaZhS6-oJ7ovc94rSRtjz_jMn2H/s921/7kspjpiq3gfYBFE.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="321" data-original-width="921" height="167" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiif6su4dE04GQyDm7D6oXewenzOOb-2vHpA0asi8HUFB0F1rkXYna3j0tsEX0Z-iGzQoGI5p0Qm4Sk2oPGvgr_zwII8TY9HS6hWK6TxS_0ODeTjvfeOsaZhS6-oJ7ovc94rSRtjz_jMn2H/w476-h167/7kspjpiq3gfYBFE.png" width="476" /></a><br /><br /><br />And suddenly, it's only a single toolchain to fix. (Almost. LTO for lld on MacOS is <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=471146">being worked on</a>).<br /><br />Sometimes, the best way to get more speed is not to change the code you wrote, but to change the way you build the software.<br /><br />Posted by Rachel Blum, Engineering Director, Chrome Desktop</div><div><br /></div><div><i>Data source for all statistics:&nbsp;<a href="https://browserbench.org/Speedometer2.0/">Speedometer 2.0</a>.</i><br /><br /></div><div class="separator" style="clear: both; text-align: center;"><br /></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><br /> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTMoYEIdhyB0zEy13cEqUkDosQm9WTI6b2uOlS2-FwwfovfDeub91dbJzjB7sVqp8JvRptqT032o0hywAGouB6SoELn9Zo6z8dRoT2_hWx-qYiTydYtltYbQt_sf2b206JRfIgAEm0xdNV/s1999/image1.jpg" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="830" data-original-width="1999" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTMoYEIdhyB0zEy13cEqUkDosQm9WTI6b2uOlS2-FwwfovfDeub91dbJzjB7sVqp8JvRptqT032o0hywAGouB6SoELn9Zo6z8dRoT2_hWx-qYiTydYtltYbQt_sf2b206JRfIgAEm0xdNV/w578-h240/image1.jpg" width="578" /></a><br /><br /><i>Chrome is fast, but there's always room for improvement. Often, that's achieved by carefully crafting the algorithms that make up Chrome. But there's a lot of Chrome, so why not let computers do at least some part of our work? In this installment of <a href="https://blog.chromium.org/search/label/the%20fast%20and%20the%20curious">The Fast And the Curious</a>, we'll show you several changes in how we build Chrome to achieve a <b>25.8% higher score on Speedometer on Windows and a 22.0% increase in browser responsiveness. </b><br /></i><br /><br /><div><h1 style="text-align: left;">Why speed?</h1>So why do we care about performance benchmarks? It's not a simple "higher numbers is better" chasing of achievements - performance was so important to Chrome that we embedded in our <a href="https://www.chromium.org/developers/core-principles">core principles</a>, the "4Ss" - Speed, Security, Stability, Simplicity. And speed matters because we want a browser that responds quickly. Speed matters so much because we want to build a faster and more responsive browser. And by improving the speed of the browser, there's the additional benefit of maximizing battery use, so you don't have to charge your laptop/devices as often.<br /><br /><br /><h1 style="text-align: left;">Speed? Size? Something Else?</h1>Let's look at a typical optimization.<br /><br /><br /></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div><span style="font-family: courier;"><span style="color: #2b00fe;">int</span> foo();</span></div><div><span style="font-family: courier;"><span style="color: #2b00fe;">int</span> fiver(<span style="color: #2b00fe;">int</span> num) {</span></div><div><span style="color: #2b00fe; font-family: courier;">&nbsp; for</span><span style="font-family: courier;">(</span><span style="color: #2b00fe; font-family: courier;">int</span><span style="font-family: courier;"> j = </span><span style="color: #38761d; font-family: courier;">0</span><span style="font-family: courier;">; j &lt; </span><span style="color: #38761d; font-family: courier;">5</span><span style="font-family: courier;">; j++)</span></div><div><span style="font-family: courier;">&nbsp; &nbsp; num = num + foo();</span></div><div><span style="font-family: courier;"><span style="color: #2b00fe;"> return</span> num;</span></div><div><span style="font-family: courier;">}</span></div></blockquote><div><br /><br />The compiler can either compile this as a loop (<a href="https://godbolt.org/z/ja7d6x7hE">smaller</a>), or turn it into five additions in a row (<a href="https://godbolt.org/z/x76PohPz9">faster, but bigger</a>)<br /><br />You save the cost of checking the end of the loop and incrementing a variable every time through the loop. But in exchange, you now have many repeated calls to foo(). If foo() is called a lot, that is a lot of space.<br /><br />And while speed matters a lot, we also care about binary size. (Yes, we see your memes!) And that tradeoff - exchanging speed for memory, and vice versa, holds for a lot of compiler optimizations.<br /><br />So how do you decide if the cost is worth it? One good way is to optimize for speed in areas that are run often, because your speed wins accumulate each time you run a function. You could just guess at what you inline (your compiler can do this, it's called "a heuristic", it's an educated guess), and then measure speed and code size.<br /><br />The result: Likely faster. Likely larger. Is that good?<br /><br />Ask any engineer a question like that, and they will answer &#8220;It depends&#8221;. So, how do you get an answer?<br /><br /><br /><h1 style="text-align: left;">The More You Know&#8230; (profiling &amp; PGO)</h1>The best way to make a decision is with data. We collect data based on what gets run a lot, and what gets run a little. We do that for several different scenarios, because our users do lots of different things with Chrome and want them to be fast.<br /><br />Our goal is collecting performance data in various scenarios, and using that to guide the compiler. There are 3 steps needed:<br /><ol style="text-align: left;"><li>Instrument for profiling</li><li>Run that instrumented executable in various scenarios</li><li>Use the resulting performance profile to guide the compiler. </li></ol><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8UX1Gvrp7O9Z9l6q7atdjs1E8XhJ4nWxlLZboPoann09dFmi9NVimkKdN_3nyMCyhOXylL70s2ip_BsgrkIhzseLa7vIK52NVFAdol5SWeASSrfG0NYL6KhugX5C4wXI0gnHx9nBkpm9l/s1999/image2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1328" data-original-width="1999" height="365" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8UX1Gvrp7O9Z9l6q7atdjs1E8XhJ4nWxlLZboPoann09dFmi9NVimkKdN_3nyMCyhOXylL70s2ip_BsgrkIhzseLa7vIK52NVFAdol5SWeASSrfG0NYL6KhugX5C4wXI0gnHx9nBkpm9l/w548-h365/image2.png" width="548" /></a></div><br /><div><br /></div><h1 style="text-align: left;">But we can do more (ThinLTO)</h1>That's a good start, but we can do better. Let's look at inlining - the compiler takes the code of a called function and inserts all of it at the callsite.<br /> <br /><br /></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div><span style="font-family: courier;"><span style="color: #2b00fe;">inline</span> int foo() { <span style="color: #2b00fe;">return</span> <span style="color: #38761d;">3</span>; };</span></div><div><span style="font-family: courier;"><span style="color: #2b00fe;">int</span> fiver_inline(<span style="color: #2b00fe;">int</span> num) {</span></div><div><span style="font-family: courier;">&nbsp; <span style="color: #2b00fe;">for</span>(<span style="color: #2b00fe;">int</span> j = <span style="color: #38761d;">0</span>; j &lt; <span style="color: #38761d;">5</span>; j++)</span></div><div><span style="font-family: courier;">&nbsp; &nbsp; num = num + foo();</span></div><div><span style="font-family: courier;"><span style="color: #2b00fe;"> return</span> num;</span></div><div><span style="font-family: courier;">}</span></div></blockquote><div><br /><br />When the compiler inlines foo(), it turns into<br /><br /></div><div><br /></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div><span style="font-family: courier;"><span style="color: #2b00fe;">int</span> fiver_inline(<span style="color: #2b00fe;">int</span> num) {</span></div><div><span style="font-family: courier;"><span style="color: #2b00fe;">&nbsp; for</span>(int j = <span style="color: #38761d;">0</span>; j &lt; <span style="color: #38761d;">5</span>; j++)</span></div><div><span style="font-family: courier;">&nbsp; &nbsp; num = num + 3;</span></div><div><span style="font-family: courier;"><span style="color: #2b00fe;"> return</span> num;</span></div><div><span style="font-family: courier;">}</span></div></blockquote><div><br /><br />Not bad - saves us the function call and all the setup that goes with having a function. But the compiler can in fact even do better - because now all the information is in one place. The compiler can apply that knowledge and deduce that fiver_inline() adds the number three and does so 5 times - and so the entire code is <a href="https://godbolt.org/z/dY1vGPYbj">boiled down to</a><br /> <br /><br /></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px;"><div style="text-align: left;"><span style="font-family: courier;"> return num + 15;</span></div></blockquote><div><br /><br />Which is awesome! But the compiler can only do this if the source code for foo() and the location where it is called are in the same source file - otherwise, the compiler does not know what to inline. (That's the fiver() example). A trivial way around that is to combine all the source files into one giant source file and compile and link that in one go.<br /><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8BzcLrQhHkvTNWkCVVYvXvGRC_a3s8XQ5WiLaUvbQZ6ipn_dafovEHOsIVPVw-E4BqniRWroaVW-02S38rYaLjyDNbrduQfOUF4tDvQIrdLe4q1-4uF8dbBHVtGc4DWXvSMawVRjAIYNz/s1999/image4.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="1329" data-original-width="1999" height="384" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8BzcLrQhHkvTNWkCVVYvXvGRC_a3s8XQ5WiLaUvbQZ6ipn_dafovEHOsIVPVw-E4BqniRWroaVW-02S38rYaLjyDNbrduQfOUF4tDvQIrdLe4q1-4uF8dbBHVtGc4DWXvSMawVRjAIYNz/w577-h384/image4.png" width="577" /></a><br /><br /><br />There's just one downside - that approach needs to generate all of the machine code for Chrome, all the time. Change one line in one file, compile all of Chrome. And there's a lot of Chrome. It also effectively disables caching build results and so makes remote compilation much less useful. (And we rely a lot on remote compilation &amp; caching so we can quickly build new versions of Chrome.)<br /><br />So, back to the drawing board. The core insight is that each source file only needs to include a few functions - it doesn't need to see every single other file. All that's needed is "cleverly" mixing the right inline functions into the right source files. <br /><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIt3Ouc89cdmpjZsdj3zaVYfBr5fjS3VYwqkW2QORzF3vhll3kDLAdvYIE_vovOWUjDwHr7DXt3UpKLesNGxBD3CszjSbf4xgDRk-AzMgMq7lTrlIIXY6rpgXx9p17Ws5aoMYEWZO5k5p4/s1999/image3.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="1329" data-original-width="1999" height="405" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIt3Ouc89cdmpjZsdj3zaVYfBr5fjS3VYwqkW2QORzF3vhll3kDLAdvYIE_vovOWUjDwHr7DXt3UpKLesNGxBD3CszjSbf4xgDRk-AzMgMq7lTrlIIXY6rpgXx9p17Ws5aoMYEWZO5k5p4/w608-h405/image3.png" width="608" /></a><br /><br /><br />Now we're back to compiling individual source files. Distributed/cached compilation works again, small changes don't cause a full rebuild, and since "ThinLTO" does just inline a few functions, and it is relatively little overhead.<br /><br />Of course, the question of "which functions should ThinLTO inline?" still needs to be answered. And the answer is still "the ones that are small and called a lot". Hey, we know those already - from the profiles we generated for Profile Guided Optimization (PGO). Talk about lucky coincidences!<br /><br /><br /><h1 style="text-align: left;">But wait, there's more! (Callgraph Sorting)</h1>We've done a lot for inlined function calls. Is there anything we can do to speed up functions that haven't been inlined, too? Turns out there is. <br /><br />One important factor is that the CPU doesn't fetch data byte by byte, but in chunks. And so, if we could ensure that a chunk of data doesn't just contain the function we need right now, but ideally also the ones that we'll need next, we could ensure that we have to go out and get chunks of data less often.<br /><br />In other words, we want functions that are called right after the other to live next to each other in memory also ("code locality"). And we already know which functions are called close to each other - because we ran our profiling and stored performance profiles for PGO.<br /><br />We can then use that information to ensure that the right functions are next to each other when we link.<br /><br /><br />I.e.<br /><br /><br /></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div><span style="font-family: courier;">g.c</span></div><div><span style="font-family: courier;">&nbsp; extern int f1();</span></div><div><span style="font-family: courier;">&nbsp; extern int f2();</span></div><div><span style="font-family: courier;">&nbsp; extern int f3();</span></div><div><span style="font-family: courier;">&nbsp; int g() {</span></div><div><span style="font-family: courier;">&nbsp; &nbsp; f1();</span></div><div><span style="font-family: courier;">&nbsp; &nbsp; for(..) {</span></div><div><span style="font-family: courier;">&nbsp; &nbsp; &nbsp; f3();</span></div><div><span style="font-family: courier;">&nbsp; }</span></div><div><span style="font-family: courier;">&nbsp; f1();</span></div><div><span style="font-family: courier;">&nbsp; f2();</span></div><div><span style="font-family: courier;">}</span></div></blockquote><div><br /><br />could be interpreted as "g() calls f3() a lot - so keep that one really close. f1() is called twice, so&#8230; somewhat close. And if we can squeeze in f2, even better". The calling sequence is a "call graph", and so this sorting process is called "call graph sorting".<br /><br />Just changing the order of functions in memory might not sound like a lot, but it leads to <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=1113282">~3% performance improvement</a>. And to know which functions calls which other ones a lot&#8230; yep. You guessed it. Our profiles from the PGO work pay off again.<br /><br /><br /><h1 style="text-align: left;">One more thing.</h1>It turns out that the compiler can make even more use of that profile data for PGO. (Not a surprise - once you know where the slow spots are, exactly, you can do a lot to improve!). To make use of that, and enable further improvements, LLVM has something called the "new pass manager". In a nutshell, it's a new way to run optimizations within LLVM, and it helps a lot with PGO. For much more detail, I'd suggest reading the <a href="https://blog.llvm.org/posts/2021-03-26-the-new-pass-manager/">LLVM blog post</a>. <br /><br />Turning that on leads to another ~3% performance increase, and ~9MB size reduction.<br /><br /></div><div><br /></div><div><h1 style="text-align: left;">Why Now?</h1>Good question. One part of that is that PGO &amp; profiling unlock an entire new set of optimizations, as you've seen above. It makes sense to do that all in one go. <br /><br />The other reason is our toolchain. We used to have a colorful mix of different technologies for compilers and linkers on different platforms.<br /><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFfNBpFNKtZU6og2qYYDDCMy-zyUx3BfEM1JtiTghtW28hCZgL8MZ3Hm-lTCyTvM-9rlUTsrKvQjPHvIzLmivvfPyjukj4a72vDkcwP2Dj5kGCwCr1cjQt1Vt79LladQN140itD6tavWMj/s916/9NcAMNnoAe52Ly9.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="319" data-original-width="916" height="166" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFfNBpFNKtZU6og2qYYDDCMy-zyUx3BfEM1JtiTghtW28hCZgL8MZ3Hm-lTCyTvM-9rlUTsrKvQjPHvIzLmivvfPyjukj4a72vDkcwP2Dj5kGCwCr1cjQt1Vt79LladQN140itD6tavWMj/w478-h166/9NcAMNnoAe52Ly9.png" width="478" /></a><br /><br /><br />And since this work requires changes to compilers and linkers, that would mean changing the build - and testing it - across 5 compilers and 4 linkers. But, thankfully, we've simplified our toolchain (Simplicity - another one of the 4S's!). To be able to do this, we worked with the LLVM community to make clang a great <a href="https://blog.llvm.org/2018/03/clang-is-now-used-to-build-chrome-for.html">Windows compiler</a>, in addition to partnering with the LLVM community to create new ELF (Linux), COFF (Windows), and Mach-O (macOS, iOS) linkers.<br /><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiif6su4dE04GQyDm7D6oXewenzOOb-2vHpA0asi8HUFB0F1rkXYna3j0tsEX0Z-iGzQoGI5p0Qm4Sk2oPGvgr_zwII8TY9HS6hWK6TxS_0ODeTjvfeOsaZhS6-oJ7ovc94rSRtjz_jMn2H/s921/7kspjpiq3gfYBFE.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="321" data-original-width="921" height="167" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiif6su4dE04GQyDm7D6oXewenzOOb-2vHpA0asi8HUFB0F1rkXYna3j0tsEX0Z-iGzQoGI5p0Qm4Sk2oPGvgr_zwII8TY9HS6hWK6TxS_0ODeTjvfeOsaZhS6-oJ7ovc94rSRtjz_jMn2H/w476-h167/7kspjpiq3gfYBFE.png" width="476" /></a><br /><br /><br />And suddenly, it's only a single toolchain to fix. (Almost. LTO for lld on MacOS is <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=471146">being worked on</a>).<br /><br />Sometimes, the best way to get more speed is not to change the code you wrote, but to change the way you build the software.<br /><br />Posted by Rachel Blum, Engineering Director, Chrome Desktop</div><div><br /></div><div><i>Data source for all statistics:&nbsp;<a href="https://browserbench.org/Speedometer2.0/">Speedometer 2.0</a>.</i><br /><br /></div><div class="separator" style="clear: both; text-align: center;"><br /></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><br /> <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:Faster Chrome - Let The Compiler do the work&url=https://blog.chromium.org/2021/12/faster-chrome-let-the-compiler-do-the-work.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/2021/12/faster-chrome-let-the-compiler-do-the-work.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/2021/12/faster-chrome-let-the-compiler-do-the-work.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> <span class='labels-caption'> Labels: </span> <span class='labels'> <a class='label' href='https://blog.chromium.org/search/label/performance' rel='tag'> performance </a> , <a class='label' href='https://blog.chromium.org/search/label/the%20fast%20and%20the%20curious' rel='tag'> the fast and the curious </a> </span> </div> </div> </div> <div class='post' data-id='4683520865210048884' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2021/11/simplified-storage-controls.html' itemprop='url' title='Simplified Storage Controls'> Simplified Storage Controls </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Thursday, November 18, 2021 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <p style="text-align: left;">Posted by&nbsp;Theodore Olsauskas-Warren</p><p>At Chrome, we&#8217;re always looking for ways to help users better understand and manage privacy on the web. Our most recent change provides more clarity on controlling site storage settings.</p><div><div>Starting today, we will be rolling out this change to M97 Beta, we will be re-configuring our Privacy and Security settings related to data a site can store (e.g. cookies). Users can now delete all data stored by an individual site by navigating to Settings &gt; Privacy and Security &gt; Site Settings &gt; View permissions and data stored across files, where they&#8217;ll land on <b>chrome://settings/content/all</b>. We will be removing the more granular controls found when navigating to Settings &gt; Privacy and Security &gt; Cookies and other site data &gt; See all cookies and site data at <b>chrome://settings/siteData</b> from Settings. This capability remains accessible for developers, the intended audience for this level of granularity, in DevTools.</div></div><table cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigGtnIWOg8hwnUzCI1bfpu1EEJKrr6vcF_hjQrDJLcnnafjkefF6JVel9huCa1CTovfVoxJwsTJt3YOUROykSbRgD_Z6RPs5cqiPzZJR8E3ios1_qTH-bplZz9Ad-mcHQKKXwBAOJLj-Of257xsXvMHvc_C3h8G3T9i7mYjUHP5P-KoalmtH35lo9fGg/s3104/storage-controls-old.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1974" data-original-width="3104" height="408" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigGtnIWOg8hwnUzCI1bfpu1EEJKrr6vcF_hjQrDJLcnnafjkefF6JVel9huCa1CTovfVoxJwsTJt3YOUROykSbRgD_Z6RPs5cqiPzZJR8E3ios1_qTH-bplZz9Ad-mcHQKKXwBAOJLj-Of257xsXvMHvc_C3h8G3T9i7mYjUHP5P-KoalmtH35lo9fGg/w640-h408/storage-controls-old.png" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;"><table cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td class="tr-caption"><span style="font-size: x-small;">OLD: We are removing this page. The controls for web-facing storage are now available at&nbsp;<b>chrome://settings/content/all</b><br /></span></td></tr></tbody></table></td><td class="tr-caption" style="text-align: center;"><br /></td></tr></tbody></table><table cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUzjfz_jfL2uB5y6W0QcnCPhC76UiJtk-rQXljtfNNX0BRJ5GhlaeVLpNHf39tqLEp_twLdVK0P1_3eyNJW_lSREGPnxnMWNpurcUMKImFc3IaZmvDea1vGW0_DfuH_1FPTFQVr64URGYrPe8_7mkmKeYPftOY_ZHudJVkH8p37WJIAnBy0F0IMAQCLQ/s3104/storage-controls-new.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1974" data-original-width="3104" height="408" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUzjfz_jfL2uB5y6W0QcnCPhC76UiJtk-rQXljtfNNX0BRJ5GhlaeVLpNHf39tqLEp_twLdVK0P1_3eyNJW_lSREGPnxnMWNpurcUMKImFc3IaZmvDea1vGW0_DfuH_1FPTFQVr64URGYrPe8_7mkmKeYPftOY_ZHudJVkH8p37WJIAnBy0F0IMAQCLQ/w640-h408/storage-controls-new.png" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;"><table cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td class="tr-caption"><span style="font-size: x-small;">NEW: Here, in&nbsp;<b>chrome://settings/content/all</b>, users will be able to delete web-facing storage.<br /></span></td></tr></tbody></table></td><td class="tr-caption"><span style="text-align: left;"><br /><br /><br /><br /><br /></span></td></tr></tbody></table><h4 style="text-align: left;">Why the change?</h4><div><div>We believe that simplifying the granular controls from Settings creates a clearer experience for users. By providing users the ability to delete individual cookies, they can accidentally change the implementation details of the site and potentially break their experience on that site, which can be difficult to predict. Even more capable users run the risk of compromising some of their privacy protection, by incorrectly assuming the purpose of a cookie.</div></div><div><div>We see this functionality being primarily used by developers, and therefore remain committed to provide them with the tools they need in DevTools. Developers can visit DevTools to continue to gain access to more technical detail on a per-cookie or per-storage level as needed.</div></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_bJJPmNDgcw6CztN9h-TSnMRpAXLbcFGx5B3baRdXYSBeKA0dMNxSqqTS_KJA6vGAzSSPVbx2_bKXEE5Pn02mltSOKQEg76QddqPJaccsLmjMGg3jcuzbcjtNrGOUehKdRArC7pC6qCiIUKrUjvRHXkzaYG8VHzY4SFXV2srNnltyX2ZEkXpcHFLDgA/s3104/storage-controls-devtools.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1974" data-original-width="3104" height="408" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_bJJPmNDgcw6CztN9h-TSnMRpAXLbcFGx5B3baRdXYSBeKA0dMNxSqqTS_KJA6vGAzSSPVbx2_bKXEE5Pn02mltSOKQEg76QddqPJaccsLmjMGg3jcuzbcjtNrGOUehKdRArC7pC6qCiIUKrUjvRHXkzaYG8VHzY4SFXV2srNnltyX2ZEkXpcHFLDgA/w640-h408/storage-controls-devtools.png" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;"><span style="font-size: x-small;">Granular cookie controls remain available in DevTools.</span></td></tr></tbody></table><div>As always, we welcome your feedback as we continue to build a more helpful Chrome. Our next step is working to remove this functionality from Page Info to keep all granular cookie controls in DevTools. If you have any other questions or comments on Storage Controls, please share them with us <a href="https://support.google.com/chrome/answer/95315">here</a>.</div> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <p style="text-align: left;">Posted by&nbsp;Theodore Olsauskas-Warren</p><p>At Chrome, we&#8217;re always looking for ways to help users better understand and manage privacy on the web. Our most recent change provides more clarity on controlling site storage settings.</p><div><div>Starting today, we will be rolling out this change to M97 Beta, we will be re-configuring our Privacy and Security settings related to data a site can store (e.g. cookies). Users can now delete all data stored by an individual site by navigating to Settings &gt; Privacy and Security &gt; Site Settings &gt; View permissions and data stored across files, where they&#8217;ll land on <b>chrome://settings/content/all</b>. We will be removing the more granular controls found when navigating to Settings &gt; Privacy and Security &gt; Cookies and other site data &gt; See all cookies and site data at <b>chrome://settings/siteData</b> from Settings. This capability remains accessible for developers, the intended audience for this level of granularity, in DevTools.</div></div><table cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigGtnIWOg8hwnUzCI1bfpu1EEJKrr6vcF_hjQrDJLcnnafjkefF6JVel9huCa1CTovfVoxJwsTJt3YOUROykSbRgD_Z6RPs5cqiPzZJR8E3ios1_qTH-bplZz9Ad-mcHQKKXwBAOJLj-Of257xsXvMHvc_C3h8G3T9i7mYjUHP5P-KoalmtH35lo9fGg/s3104/storage-controls-old.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1974" data-original-width="3104" height="408" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigGtnIWOg8hwnUzCI1bfpu1EEJKrr6vcF_hjQrDJLcnnafjkefF6JVel9huCa1CTovfVoxJwsTJt3YOUROykSbRgD_Z6RPs5cqiPzZJR8E3ios1_qTH-bplZz9Ad-mcHQKKXwBAOJLj-Of257xsXvMHvc_C3h8G3T9i7mYjUHP5P-KoalmtH35lo9fGg/w640-h408/storage-controls-old.png" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;"><table cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td class="tr-caption"><span style="font-size: x-small;">OLD: We are removing this page. The controls for web-facing storage are now available at&nbsp;<b>chrome://settings/content/all</b><br /></span></td></tr></tbody></table></td><td class="tr-caption" style="text-align: center;"><br /></td></tr></tbody></table><table cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUzjfz_jfL2uB5y6W0QcnCPhC76UiJtk-rQXljtfNNX0BRJ5GhlaeVLpNHf39tqLEp_twLdVK0P1_3eyNJW_lSREGPnxnMWNpurcUMKImFc3IaZmvDea1vGW0_DfuH_1FPTFQVr64URGYrPe8_7mkmKeYPftOY_ZHudJVkH8p37WJIAnBy0F0IMAQCLQ/s3104/storage-controls-new.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1974" data-original-width="3104" height="408" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUzjfz_jfL2uB5y6W0QcnCPhC76UiJtk-rQXljtfNNX0BRJ5GhlaeVLpNHf39tqLEp_twLdVK0P1_3eyNJW_lSREGPnxnMWNpurcUMKImFc3IaZmvDea1vGW0_DfuH_1FPTFQVr64URGYrPe8_7mkmKeYPftOY_ZHudJVkH8p37WJIAnBy0F0IMAQCLQ/w640-h408/storage-controls-new.png" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;"><table cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td class="tr-caption"><span style="font-size: x-small;">NEW: Here, in&nbsp;<b>chrome://settings/content/all</b>, users will be able to delete web-facing storage.<br /></span></td></tr></tbody></table></td><td class="tr-caption"><span style="text-align: left;"><br /><br /><br /><br /><br /></span></td></tr></tbody></table><h4 style="text-align: left;">Why the change?</h4><div><div>We believe that simplifying the granular controls from Settings creates a clearer experience for users. By providing users the ability to delete individual cookies, they can accidentally change the implementation details of the site and potentially break their experience on that site, which can be difficult to predict. Even more capable users run the risk of compromising some of their privacy protection, by incorrectly assuming the purpose of a cookie.</div></div><div><div>We see this functionality being primarily used by developers, and therefore remain committed to provide them with the tools they need in DevTools. Developers can visit DevTools to continue to gain access to more technical detail on a per-cookie or per-storage level as needed.</div></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_bJJPmNDgcw6CztN9h-TSnMRpAXLbcFGx5B3baRdXYSBeKA0dMNxSqqTS_KJA6vGAzSSPVbx2_bKXEE5Pn02mltSOKQEg76QddqPJaccsLmjMGg3jcuzbcjtNrGOUehKdRArC7pC6qCiIUKrUjvRHXkzaYG8VHzY4SFXV2srNnltyX2ZEkXpcHFLDgA/s3104/storage-controls-devtools.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1974" data-original-width="3104" height="408" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_bJJPmNDgcw6CztN9h-TSnMRpAXLbcFGx5B3baRdXYSBeKA0dMNxSqqTS_KJA6vGAzSSPVbx2_bKXEE5Pn02mltSOKQEg76QddqPJaccsLmjMGg3jcuzbcjtNrGOUehKdRArC7pC6qCiIUKrUjvRHXkzaYG8VHzY4SFXV2srNnltyX2ZEkXpcHFLDgA/w640-h408/storage-controls-devtools.png" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;"><span style="font-size: x-small;">Granular cookie controls remain available in DevTools.</span></td></tr></tbody></table><div>As always, we welcome your feedback as we continue to build a more helpful Chrome. Our next step is working to remove this functionality from Page Info to keep all granular cookie controls in DevTools. If you have any other questions or comments on Storage Controls, please share them with us <a href="https://support.google.com/chrome/answer/95315">here</a>.</div> <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:Simplified Storage Controls&url=https://blog.chromium.org/2021/11/simplified-storage-controls.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/2021/11/simplified-storage-controls.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/2021/11/simplified-storage-controls.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='5663750506474401705' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2021/11/chrome-97-webtransport-new-array-static.html' itemprop='url' title='Chrome 97: WebTransport, New Array Static Methods and More'> Chrome 97: WebTransport, New Array Static Methods and More </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Thursday, November 18, 2021 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <p>Unless otherwise noted, changes described below apply to the newest Chrome beta channel release for Android, Chrome OS, Linux, macOS, and Windows. Learn more about the features listed here through the provided links. Chrome 97 is beta as of November 18, 2021.</p> <h1>Preparing for a Three Digit Version Number</h1> <p>Next year, Chrome will release version 100. This will add a digit to the version number reported in Chrome's user agent string. To help site owners test for the new string, Chrome 96 introduces a runtime flag that causes Chrome to return '100' in its user agent string. This new flag called <code>chrome://flags/#force-major-version-to-100</code> is available from Chrome 96 onward. For more information, see&nbsp;<a href="https://developer.chrome.com/blog/force-major-version-to-100/">Force Chrome major version to 100 in the User-Agent string.</a></p> <h1>Features in this Release</h1> <h2>Auto-expand Details Elements</h2> <p>Closed details elements are now searchable and can now be linked to. These hidden elements will also automatically expand when <code>find-in-page</code>, <code>ScrollToTextFragment</code>, and element fragment navigation are used. </p> <h2>Content-Security-Policy Delivery via Response Headers for Dedicated Workers.</h2> <p>Dedicated workers are <a href="https://www.chromestatus.com/feature/5715844005888000">now governed by Content Security Policy</a>. Previously, Chrome incorrectly applied the Content Security Policy of the owner document.</p> <h2>CSS</h2><h3 style="text-align: left;">font-synthesis Property</h3> <p>The <a href="https://www.chromestatus.com/feature/5640605355999232"><code>font-synthesis</code> CSS property</a> controls whether user agents are allowed to synthesize oblique, bold, and small-caps font faces when a font family lacks oblique, bold, and small-caps faces, respectively. Without the <code>font-synthesis</code> property some web pages that do not have font families with the required variations may have unnatural forms of fonts</p> <h3>transform: perspective(none)</h3> <p>The <code>perspective()</code> function now <a href="https://www.chromestatus.com/feature/5687325523705856">supports the value <code>'none'</code> as an argument</a>. This causes the function to behave as though it were passed an argument that is infinite. This makes it easier (or, in some cases, possible) to do animations involving the <code>perspective()</code> function where one of the endpoints of the animation is the identity matrix.</p> <h2>Feature Policy for Keyboard API</h2> <p>Chrome supports a <a href="https://www.chromestatus.com/feature/5657965899022336">new <code>keyboard-map</code> value</a> for the allow list of a feature policy. <code>Keyboard.getLayoutMap()</code> helps identify a key pressed key for different keyboard layouts such as English and French. This method is unavailable in iframe elements. The architecture of some web apps (Excel, Word, and PowerPoint) that could not use the Keyboard API can now do so.</p> <h2>HTMLScriptElement.supports() Method</h2> <p>The <a href="https://www.chromestatus.com/feature/5712146835963904"><code>HTMLScriptElement.supports()</code> method</a> provides a unified way to detect new features that use script elements. Currently there is no simple way to know what kind of types can be used for the type attribute of <code>HTMLScriptElement</code>.</p> <h2>Late Newline Normalization in Form Submission</h2> <p>Newlines in form entries are <a href="https://www.chromestatus.com/feature/5654547184746496">now normalized the same as Gecko and WebKit</a>, solving a long-standing interoperability problem where Gecko and WebKit normalized newlines late, while Chrome did them early. Starting in Chrome 97, early normalization is removed and late normalization is extended to all encoding types.</p> <h2>Standardize Existing Client Hint Naming</h2> <p>Chrome 97 standardizes client hint names by <a href="https://www.chromestatus.com/feature/6658223894429696">prefixing them with <code>Sec-CH-</code></a>. Affected client hints are <code>dpr</code>, <code>width</code>, <code>viewport-width</code>, <code>device-memory</code>, <code>rtt</code>, <code>downlink</code>, and <code>ect</code>. Chrome will continue to support existing versions of these hints. Nevertheless, web developers should plan for their eventual deprecation and removal. </p> <h2>WebTransport</h2> <p>WebTransport is a protocol framework that enables clients constrained by the Web security model to communicate with a remote server using a secure multiplexed transport.</p> <p>Currently, Web application developers have two APIs for bidirectional communications with a remote server: <code>WebSockets</code> and <code>RTCDataChannel</code>. <code>WebSockets</code> are TCP-based, thus having all of the drawbacks of TCP (head of line blocking, lack of support for unreliable data transport) that make it a poor fit for latency-sensitive applications. <code>RTCDataChannel</code> is based on the Stream Control Transmission Protocol (SCTP), which does not have these drawbacks; however, it is designed to be used in a peer-to-peer context, which causes its use in client-server settings to be fairly low. <code>WebTransport</code> provides a client-server API that supports bidirectional transfer of both unreliable and reliable data, using UDP-like datagrams and cancellable streams. <code>WebTransport</code> calls are visible in the Network panel of DevTools and identified as such in the Type column. </p> <p>For more information, see <a href="https://web.dev/webtransport/">Experimenting with WebTransport</a>. </p> <h1>JavaScript</h1> <p>This version of Chrome incorporates version x.x of the V8 JavaScript engine. It specifically includes the changes listed below. You can find a complete <a href="https://v8.dev/blog">list of recent features</a> in the V8 release notes.</p> <h2>Array and TypedArray findLast() and findLastIndex()</h2> <p><code>Array</code> and <code>TypedArray</code> now support the <a href="https://chromestatus.com/feature/5693639729610752"><code>findLast()</code> and <code>fileLastIndex()</code> static methods</a>. These functions are analogous to <code>find()</code> and <code>findIndex()</code> but search from the end of an array instead of the beginning.</p> <h1>Deprecations and Removals</h1> <p>This version of Chrome introduces the deprecations and removals listed below. Visit ChromeStatus.com for lists of <a href="https://www.chromestatus.com/features#browsers.chrome.status%3A%22Deprecated%22">current deprecations</a> and <a href="https://www.chromestatus.com/features#browsers.chrome.status:%22Removed%22">previous removals</a>.</p> <h2>Remove SDES Key Exchange for WebRTC</h2> <p>The SDES key exchange mechanism for WebRTC has been declared a MUST NOT in the relevant IETF standards since 2013. The SDES specification has been declared historic by the IETF. Its usage in Chrome has declined significantly over the recent year. Consequently <a href="https://www.chromestatus.com/feature/5695324321480704">it is removed</a> as of Chrome 97.</p> <h2>Remove WebSQL in Third-Party Contexts</h2> <p><a href="https://www.chromestatus.com/feature/5684870116278272">WebSQL in third-party contexts is now removed</a>. The Web SQL Database standard was first proposed in April 2009 and abandoned in November 2010. Gecko never implemented this feature and WebKit deprecated it in 2019. The W3C encourages <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API">Web Storage</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API">Indexed Database</a> for those needing alternatives.</p> <h2>Remove SDP Plan B</h2> <p>The Session Description Protocol (SDP) used to establish a session in WebRTC has been implemented with two different dialects in Chromium: Unified Plan and Plan B. Plan B is not cross-browser compatible and <a href="https://www.chromestatus.com/features/5823036655665152">is hereby removed</a>. </p> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <p>Unless otherwise noted, changes described below apply to the newest Chrome beta channel release for Android, Chrome OS, Linux, macOS, and Windows. Learn more about the features listed here through the provided links. Chrome 97 is beta as of November 18, 2021.</p> <h1>Preparing for a Three Digit Version Number</h1> <p>Next year, Chrome will release version 100. This will add a digit to the version number reported in Chrome's user agent string. To help site owners test for the new string, Chrome 96 introduces a runtime flag that causes Chrome to return '100' in its user agent string. This new flag called <code>chrome://flags/#force-major-version-to-100</code> is available from Chrome 96 onward. For more information, see&nbsp;<a href="https://developer.chrome.com/blog/force-major-version-to-100/">Force Chrome major version to 100 in the User-Agent string.</a></p> <h1>Features in this Release</h1> <h2>Auto-expand Details Elements</h2> <p>Closed details elements are now searchable and can now be linked to. These hidden elements will also automatically expand when <code>find-in-page</code>, <code>ScrollToTextFragment</code>, and element fragment navigation are used. </p> <h2>Content-Security-Policy Delivery via Response Headers for Dedicated Workers.</h2> <p>Dedicated workers are <a href="https://www.chromestatus.com/feature/5715844005888000">now governed by Content Security Policy</a>. Previously, Chrome incorrectly applied the Content Security Policy of the owner document.</p> <h2>CSS</h2><h3 style="text-align: left;">font-synthesis Property</h3> <p>The <a href="https://www.chromestatus.com/feature/5640605355999232"><code>font-synthesis</code> CSS property</a> controls whether user agents are allowed to synthesize oblique, bold, and small-caps font faces when a font family lacks oblique, bold, and small-caps faces, respectively. Without the <code>font-synthesis</code> property some web pages that do not have font families with the required variations may have unnatural forms of fonts</p> <h3>transform: perspective(none)</h3> <p>The <code>perspective()</code> function now <a href="https://www.chromestatus.com/feature/5687325523705856">supports the value <code>'none'</code> as an argument</a>. This causes the function to behave as though it were passed an argument that is infinite. This makes it easier (or, in some cases, possible) to do animations involving the <code>perspective()</code> function where one of the endpoints of the animation is the identity matrix.</p> <h2>Feature Policy for Keyboard API</h2> <p>Chrome supports a <a href="https://www.chromestatus.com/feature/5657965899022336">new <code>keyboard-map</code> value</a> for the allow list of a feature policy. <code>Keyboard.getLayoutMap()</code> helps identify a key pressed key for different keyboard layouts such as English and French. This method is unavailable in iframe elements. The architecture of some web apps (Excel, Word, and PowerPoint) that could not use the Keyboard API can now do so.</p> <h2>HTMLScriptElement.supports() Method</h2> <p>The <a href="https://www.chromestatus.com/feature/5712146835963904"><code>HTMLScriptElement.supports()</code> method</a> provides a unified way to detect new features that use script elements. Currently there is no simple way to know what kind of types can be used for the type attribute of <code>HTMLScriptElement</code>.</p> <h2>Late Newline Normalization in Form Submission</h2> <p>Newlines in form entries are <a href="https://www.chromestatus.com/feature/5654547184746496">now normalized the same as Gecko and WebKit</a>, solving a long-standing interoperability problem where Gecko and WebKit normalized newlines late, while Chrome did them early. Starting in Chrome 97, early normalization is removed and late normalization is extended to all encoding types.</p> <h2>Standardize Existing Client Hint Naming</h2> <p>Chrome 97 standardizes client hint names by <a href="https://www.chromestatus.com/feature/6658223894429696">prefixing them with <code>Sec-CH-</code></a>. Affected client hints are <code>dpr</code>, <code>width</code>, <code>viewport-width</code>, <code>device-memory</code>, <code>rtt</code>, <code>downlink</code>, and <code>ect</code>. Chrome will continue to support existing versions of these hints. Nevertheless, web developers should plan for their eventual deprecation and removal. </p> <h2>WebTransport</h2> <p>WebTransport is a protocol framework that enables clients constrained by the Web security model to communicate with a remote server using a secure multiplexed transport.</p> <p>Currently, Web application developers have two APIs for bidirectional communications with a remote server: <code>WebSockets</code> and <code>RTCDataChannel</code>. <code>WebSockets</code> are TCP-based, thus having all of the drawbacks of TCP (head of line blocking, lack of support for unreliable data transport) that make it a poor fit for latency-sensitive applications. <code>RTCDataChannel</code> is based on the Stream Control Transmission Protocol (SCTP), which does not have these drawbacks; however, it is designed to be used in a peer-to-peer context, which causes its use in client-server settings to be fairly low. <code>WebTransport</code> provides a client-server API that supports bidirectional transfer of both unreliable and reliable data, using UDP-like datagrams and cancellable streams. <code>WebTransport</code> calls are visible in the Network panel of DevTools and identified as such in the Type column. </p> <p>For more information, see <a href="https://web.dev/webtransport/">Experimenting with WebTransport</a>. </p> <h1>JavaScript</h1> <p>This version of Chrome incorporates version x.x of the V8 JavaScript engine. It specifically includes the changes listed below. You can find a complete <a href="https://v8.dev/blog">list of recent features</a> in the V8 release notes.</p> <h2>Array and TypedArray findLast() and findLastIndex()</h2> <p><code>Array</code> and <code>TypedArray</code> now support the <a href="https://chromestatus.com/feature/5693639729610752"><code>findLast()</code> and <code>fileLastIndex()</code> static methods</a>. These functions are analogous to <code>find()</code> and <code>findIndex()</code> but search from the end of an array instead of the beginning.</p> <h1>Deprecations and Removals</h1> <p>This version of Chrome introduces the deprecations and removals listed below. Visit ChromeStatus.com for lists of <a href="https://www.chromestatus.com/features#browsers.chrome.status%3A%22Deprecated%22">current deprecations</a> and <a href="https://www.chromestatus.com/features#browsers.chrome.status:%22Removed%22">previous removals</a>.</p> <h2>Remove SDES Key Exchange for WebRTC</h2> <p>The SDES key exchange mechanism for WebRTC has been declared a MUST NOT in the relevant IETF standards since 2013. The SDES specification has been declared historic by the IETF. Its usage in Chrome has declined significantly over the recent year. Consequently <a href="https://www.chromestatus.com/feature/5695324321480704">it is removed</a> as of Chrome 97.</p> <h2>Remove WebSQL in Third-Party Contexts</h2> <p><a href="https://www.chromestatus.com/feature/5684870116278272">WebSQL in third-party contexts is now removed</a>. The Web SQL Database standard was first proposed in April 2009 and abandoned in November 2010. Gecko never implemented this feature and WebKit deprecated it in 2019. The W3C encourages <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API">Web Storage</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API">Indexed Database</a> for those needing alternatives.</p> <h2>Remove SDP Plan B</h2> <p>The Session Description Protocol (SDP) used to establish a session in WebRTC has been implemented with two different dialects in Chromium: Unified Plan and Plan B. Plan B is not cross-browser compatible and <a href="https://www.chromestatus.com/features/5823036655665152">is hereby removed</a>. </p> <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 97: WebTransport, New Array Static Methods and More&url=https://blog.chromium.org/2021/11/chrome-97-webtransport-new-array-static.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/2021/11/chrome-97-webtransport-new-array-static.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/2021/11/chrome-97-webtransport-new-array-static.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='881381226400304116' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2021/11/chrome-android-faster-launch-times-less-memory.html' itemprop='url' title='Partitioning Chrome&#39;s Code for Faster Launch Times on Android'> Partitioning Chrome's Code for Faster Launch Times on Android </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Tuesday, November 16, 2021 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_eTPCgvctptMUoaEQFYiazoT2yt8d2c1HP0Kyd8zjU-myIYnMhOQyyyHK7gRHC_beCFhaYt0tXfnAOadUR3G9yZFJT9xX4b0wvZE7ny30MWQonXpD9oVvNccCoecbck3GwBwMIGRHdGlv/s1999/image1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="830" data-original-width="1999" height="277" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_eTPCgvctptMUoaEQFYiazoT2yt8d2c1HP0Kyd8zjU-myIYnMhOQyyyHK7gRHC_beCFhaYt0tXfnAOadUR3G9yZFJT9xX4b0wvZE7ny30MWQonXpD9oVvNccCoecbck3GwBwMIGRHdGlv/w667-h277/image1.jpg" width="667" /></a><br /><br /><i>Mobile devices are generally more resource constrained than laptops or desktops. Optimizing Chrome&#8217;s resource usage is critical to give mobile users a faster Chrome experience. As we&#8217;ve added features to Chrome on Android, the amount of Java code packaged in the app has continued to grow. In this <a href="https://blog.chromium.org/search/label/the%20fast%20and%20the%20curious">The Fast and the Curious</a> post we show how our team improved the speed and memory usage of Chrome on Android with Isolated Splits. With these improvements, Chrome on Android now <b>uses 5-7% less memory, and starts and loads pages even faster than before.</b></i><br /><br /><div><h1 style="text-align: left;">The Problem</h1>For Android apps (including Chrome on Android), compiled Java code is stored in <a href="https://source.android.com/devices/tech/dalvik/dex-format">.dex files</a>. The user's experience in Chrome on Android is particularly sensitive to increases in .dex size due to its <a href="https://developers.google.com/web/updates/2018/09/inside-browser-part1#browser-architecture">multi-process architecture</a>. On Android, Chrome will generally have 3+ processes running at all times: the browser process, the GPU process, and one or more renderer processes. The vast majority of Chrome&#8217;s Java code is used only in the browser process, but the performance and memory cost of loading the code is paid by all processes.</div><div>&nbsp; <br /><h1 style="text-align: left;">Bundles and Feature Modules</h1>Ideally, we would load the smallest chunk of Java necessary for a process to run. We can get close to this by using <a href="https://developer.android.com/guide/app-bundle">Android App Bundles</a> and splitting code into <a href="https://developer.android.com/guide/playcore/feature-delivery">feature modules</a>. Feature modules allow splitting code, resources, and assets into distinct <a href="https://source.android.com/setup/start/glossary#apk">APKs</a> installed alongside the base APK, either on-demand or during app install.<br /><br />Now, it seems like we have exactly what we want: a feature module could be created for the browser process code, which could be loaded when needed. However, this is not how Android loads feature modules. By default, all installed feature modules are loaded on startup. For an app with a base module and three feature modules &#8220;a&#8221;, &#8220;b&#8221;, and &#8220;c&#8221;, this gives us an Android <a href="https://developer.android.com/reference/android/content/Context">Context</a> with a <a href="https://developer.android.com/reference/java/lang/ClassLoader">ClassLoader</a> that looks something like this:<br /><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5ToLkPUoIoeIlBiTgDz9VheKZPfx6416hVZybfNRAS56KROGcSi5l9iaLbRSu-hBvVEfrhewznscqVP1oReCvFsDBeeRNvh9ZWMJD2gcr-BvrV2JQ2RuWZ7V-SNb26ZwW0ktUXR3iFN3K/s1999/image1.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="1329" data-original-width="1999" height="438" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5ToLkPUoIoeIlBiTgDz9VheKZPfx6416hVZybfNRAS56KROGcSi5l9iaLbRSu-hBvVEfrhewznscqVP1oReCvFsDBeeRNvh9ZWMJD2gcr-BvrV2JQ2RuWZ7V-SNb26ZwW0ktUXR3iFN3K/w658-h438/image1.png" width="658" /></a><br /><br /><br />Having a small minimum set of installed modules that are all immediately loaded at startup is beneficial in some situations. For example, if an app has a large feature that is needed only for a subset of users, the app could avoid installing it entirely for users who don't need it. However, for more commonly used features, having to download a feature at runtime can introduce user friction -- for example, additional latency or challenges if mobile data is unavailable. Ideally we'd be able to have all of our standard modules installed ahead of time, but loaded only when they're actually needed.</div><div><br /><h1 style="text-align: left;">Isolated Splits to the Rescue</h1>A few days of spelunking in the Android source code led us to the <a href="https://developer.android.com/reference/android/R.attr#isolatedSplits">android:isolatedSplits</a> attribute. If this is set to &#8220;true&#8221;, each installed split APK will not be loaded during start-up, and instead must be loaded explicitly. This is exactly what we want to allow our processes to use less resources! The ClassLoader illustrated above now looks like this:<br /><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRY3-zoPoxnBcXGmyM1IkZjFpvI9In9vIuzhGiamzSWOGM-Olt5grMUqpK7DgUpn7LhQBxAxB0DWJ6xwkmQPOzTs5Xard0wtvE_HHoVivRQVYVnf8NZv_eEzJqCTeIbZGBs60-s5t9DH5q/s1999/image3.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="1329" data-original-width="1999" height="434" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRY3-zoPoxnBcXGmyM1IkZjFpvI9In9vIuzhGiamzSWOGM-Olt5grMUqpK7DgUpn7LhQBxAxB0DWJ6xwkmQPOzTs5Xard0wtvE_HHoVivRQVYVnf8NZv_eEzJqCTeIbZGBs60-s5t9DH5q/w652-h434/image3.png" width="652" /></a><br /><br /><br />In Chrome&#8217;s case, the small amount of code needed in the renderer and GPU processes can be kept in the base module, and the browser code and other expensive features can be split into feature modules to be loaded when needed. Using this method, we were able to reduce the .dex size loaded in child processes by 75% to ~2.5MB, making them start faster and use less memory.<br /><br />This architecture also enabled optimizations for the browser process. We were able to improve startup time by preloading the majority of the browser process code on a background thread while the Application initializes leading to a 7.6% faster load time. By the time an Activity or other component which needed the browser code was launched, it would already be loaded. By optimizing how features are allocated into feature modules, features can be loaded on-demand which saves the memory and loading cost until the feature is used.</div><div><br /><h1 style="text-align: left;">Results</h1>Since <a href="https://blog.chromium.org/2021/03/advanced-memory-management-and-more.html">Chrome shipped with isolated splits in M89</a> we now have several months of data from the field, and are pleased to share significant improvements in memory usage, startup time, page load speed, and stability for all Chrome on Android users running Android Oreo or later:<br /><ul style="text-align: left;"><li>Median total memory usage improved by 5.2%</li><li>Median renderer process memory usage improved by 7.9%</li><li>Median GPU process memory usage improved by 7.6%</li><li>Median browser process memory usage improved by 1.2%</li><li>95th percentile startup time improved by 7.6%</li><li>95th percentile page load speed improved by 2.3%</li><li>Large improvements in both browser crash rate and renderer hang rate</li></ul>Posted by&nbsp;Clark Duvall, Chrome Software Engineer<br /><br /><i>Data source for all statistics: <a href="https://www.google.com/chrome/privacy/whitepaper.html#usagestats">Real-world data</a> anonymously aggregated from Chrome clients.</i></div><br /> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_eTPCgvctptMUoaEQFYiazoT2yt8d2c1HP0Kyd8zjU-myIYnMhOQyyyHK7gRHC_beCFhaYt0tXfnAOadUR3G9yZFJT9xX4b0wvZE7ny30MWQonXpD9oVvNccCoecbck3GwBwMIGRHdGlv/s1999/image1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="830" data-original-width="1999" height="277" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_eTPCgvctptMUoaEQFYiazoT2yt8d2c1HP0Kyd8zjU-myIYnMhOQyyyHK7gRHC_beCFhaYt0tXfnAOadUR3G9yZFJT9xX4b0wvZE7ny30MWQonXpD9oVvNccCoecbck3GwBwMIGRHdGlv/w667-h277/image1.jpg" width="667" /></a><br /><br /><i>Mobile devices are generally more resource constrained than laptops or desktops. Optimizing Chrome&#8217;s resource usage is critical to give mobile users a faster Chrome experience. As we&#8217;ve added features to Chrome on Android, the amount of Java code packaged in the app has continued to grow. In this <a href="https://blog.chromium.org/search/label/the%20fast%20and%20the%20curious">The Fast and the Curious</a> post we show how our team improved the speed and memory usage of Chrome on Android with Isolated Splits. With these improvements, Chrome on Android now <b>uses 5-7% less memory, and starts and loads pages even faster than before.</b></i><br /><br /><div><h1 style="text-align: left;">The Problem</h1>For Android apps (including Chrome on Android), compiled Java code is stored in <a href="https://source.android.com/devices/tech/dalvik/dex-format">.dex files</a>. The user's experience in Chrome on Android is particularly sensitive to increases in .dex size due to its <a href="https://developers.google.com/web/updates/2018/09/inside-browser-part1#browser-architecture">multi-process architecture</a>. On Android, Chrome will generally have 3+ processes running at all times: the browser process, the GPU process, and one or more renderer processes. The vast majority of Chrome&#8217;s Java code is used only in the browser process, but the performance and memory cost of loading the code is paid by all processes.</div><div>&nbsp; <br /><h1 style="text-align: left;">Bundles and Feature Modules</h1>Ideally, we would load the smallest chunk of Java necessary for a process to run. We can get close to this by using <a href="https://developer.android.com/guide/app-bundle">Android App Bundles</a> and splitting code into <a href="https://developer.android.com/guide/playcore/feature-delivery">feature modules</a>. Feature modules allow splitting code, resources, and assets into distinct <a href="https://source.android.com/setup/start/glossary#apk">APKs</a> installed alongside the base APK, either on-demand or during app install.<br /><br />Now, it seems like we have exactly what we want: a feature module could be created for the browser process code, which could be loaded when needed. However, this is not how Android loads feature modules. By default, all installed feature modules are loaded on startup. For an app with a base module and three feature modules &#8220;a&#8221;, &#8220;b&#8221;, and &#8220;c&#8221;, this gives us an Android <a href="https://developer.android.com/reference/android/content/Context">Context</a> with a <a href="https://developer.android.com/reference/java/lang/ClassLoader">ClassLoader</a> that looks something like this:<br /><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5ToLkPUoIoeIlBiTgDz9VheKZPfx6416hVZybfNRAS56KROGcSi5l9iaLbRSu-hBvVEfrhewznscqVP1oReCvFsDBeeRNvh9ZWMJD2gcr-BvrV2JQ2RuWZ7V-SNb26ZwW0ktUXR3iFN3K/s1999/image1.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="1329" data-original-width="1999" height="438" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5ToLkPUoIoeIlBiTgDz9VheKZPfx6416hVZybfNRAS56KROGcSi5l9iaLbRSu-hBvVEfrhewznscqVP1oReCvFsDBeeRNvh9ZWMJD2gcr-BvrV2JQ2RuWZ7V-SNb26ZwW0ktUXR3iFN3K/w658-h438/image1.png" width="658" /></a><br /><br /><br />Having a small minimum set of installed modules that are all immediately loaded at startup is beneficial in some situations. For example, if an app has a large feature that is needed only for a subset of users, the app could avoid installing it entirely for users who don't need it. However, for more commonly used features, having to download a feature at runtime can introduce user friction -- for example, additional latency or challenges if mobile data is unavailable. Ideally we'd be able to have all of our standard modules installed ahead of time, but loaded only when they're actually needed.</div><div><br /><h1 style="text-align: left;">Isolated Splits to the Rescue</h1>A few days of spelunking in the Android source code led us to the <a href="https://developer.android.com/reference/android/R.attr#isolatedSplits">android:isolatedSplits</a> attribute. If this is set to &#8220;true&#8221;, each installed split APK will not be loaded during start-up, and instead must be loaded explicitly. This is exactly what we want to allow our processes to use less resources! The ClassLoader illustrated above now looks like this:<br /><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRY3-zoPoxnBcXGmyM1IkZjFpvI9In9vIuzhGiamzSWOGM-Olt5grMUqpK7DgUpn7LhQBxAxB0DWJ6xwkmQPOzTs5Xard0wtvE_HHoVivRQVYVnf8NZv_eEzJqCTeIbZGBs60-s5t9DH5q/s1999/image3.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="1329" data-original-width="1999" height="434" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRY3-zoPoxnBcXGmyM1IkZjFpvI9In9vIuzhGiamzSWOGM-Olt5grMUqpK7DgUpn7LhQBxAxB0DWJ6xwkmQPOzTs5Xard0wtvE_HHoVivRQVYVnf8NZv_eEzJqCTeIbZGBs60-s5t9DH5q/w652-h434/image3.png" width="652" /></a><br /><br /><br />In Chrome&#8217;s case, the small amount of code needed in the renderer and GPU processes can be kept in the base module, and the browser code and other expensive features can be split into feature modules to be loaded when needed. Using this method, we were able to reduce the .dex size loaded in child processes by 75% to ~2.5MB, making them start faster and use less memory.<br /><br />This architecture also enabled optimizations for the browser process. We were able to improve startup time by preloading the majority of the browser process code on a background thread while the Application initializes leading to a 7.6% faster load time. By the time an Activity or other component which needed the browser code was launched, it would already be loaded. By optimizing how features are allocated into feature modules, features can be loaded on-demand which saves the memory and loading cost until the feature is used.</div><div><br /><h1 style="text-align: left;">Results</h1>Since <a href="https://blog.chromium.org/2021/03/advanced-memory-management-and-more.html">Chrome shipped with isolated splits in M89</a> we now have several months of data from the field, and are pleased to share significant improvements in memory usage, startup time, page load speed, and stability for all Chrome on Android users running Android Oreo or later:<br /><ul style="text-align: left;"><li>Median total memory usage improved by 5.2%</li><li>Median renderer process memory usage improved by 7.9%</li><li>Median GPU process memory usage improved by 7.6%</li><li>Median browser process memory usage improved by 1.2%</li><li>95th percentile startup time improved by 7.6%</li><li>95th percentile page load speed improved by 2.3%</li><li>Large improvements in both browser crash rate and renderer hang rate</li></ul>Posted by&nbsp;Clark Duvall, Chrome Software Engineer<br /><br /><i>Data source for all statistics: <a href="https://www.google.com/chrome/privacy/whitepaper.html#usagestats">Real-world data</a> anonymously aggregated from Chrome clients.</i></div><br /> <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:Partitioning Chrome&#39;s Code for Faster Launch Times on Android&url=https://blog.chromium.org/2021/11/chrome-android-faster-launch-times-less-memory.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/2021/11/chrome-android-faster-launch-times-less-memory.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/2021/11/chrome-android-faster-launch-times-less-memory.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> <span class='labels-caption'> Labels: </span> <span class='labels'> <a class='label' href='https://blog.chromium.org/search/label/performance' rel='tag'> performance </a> , <a class='label' href='https://blog.chromium.org/search/label/the%20fast%20and%20the%20curious' rel='tag'> the fast and the curious </a> </span> </div> </div> </div> <div class='post' data-id='3027035215206834389' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2021/11/chrome-dev-summit-2021-moving-toward.html' itemprop='url' title='Chrome Dev Summit 2021: Moving toward a more powerful and private web'> Chrome Dev Summit 2021: Moving toward a more powerful and private web </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Wednesday, November 3, 2021 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <span class="post-author">By Paul Kinlan, Lead for Chrome Developer Relations</span> <p>The big day is finally here. Today, at Chrome Dev Summit 2021 we shared some of the highlights of what we've been working on &#8212; the latest product updates, vision for the web's future and examples of best-in-class web experiences. Over the past year, we've also had a lot of feedback that you want to spend more time learning from and working with the Chrome team and other industry experts. I'm excited to share with you that <a href="https://developer.chrome.com/devsummit/schedule/">we've opened up a lot of spaces for 1:1 office hours, workshops and learning lounges</a> to give you more opportunity to connect with the Chrome team.</p> <p>It's been a busy year for us all and with the continued shift of people moving more of their lives online, it has been more important than ever for us to <a href="https://web.dev/compat2021-midyear/">continue investing in Web Compat</a>, and we've been amazed to see the <a href="https://wpt.fyi/compat2021?feature=summary">improvements in compatibility across the board</a> that is helping to make it easier for you to build sites that work across all browsers for everyone who uses the web.</p> <p>We've also got a number of important updates to core topics that are important to every developer:</p> <ul> <li>An update on how we're helping to shift the web towards more privacy-safe technologies and give you more visibility into that process.</li> <li>A showcase on how many major companies have bet on the web and brough advanced app-like experiences to anyone who can use a browser.</li> <li>An update on Core Web Vitals and some new tools that will make it easier for you to measure your sites.</li> <li>A dive into the "New Responsive" with highlights of new tools and capabilities for designers that make it easier than ever to build experiences your users love.</li> </ul> <p>This post is an overview of the latest updates from this year's Chrome Dev Summit keynote. </p><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="331" src="https://www.youtube.com/embed/n57U2_-3NLQ" width="486" youtube-src-id="n57U2_-3NLQ"></iframe></div><br /> <h2 style="text-align: left;">Paving a Path Toward a More Secure Web</h2> <p>The <a href="https://privacysandbox.com/">Privacy Sandbox</a> continues to be a cornerstone of our ongoing efforts to collaboratively build privacy-preserving technologies for a healthy web. Our <a href="https://privacysandbox.com/timeline/">development timeline</a>, which we'll update monthly, shares when developers and advertisers can expect these technologies to be ready for testing and scaled adoption.<br /> This timeline reflects three developmental phases for Privacy Sandbox proposals:</p> <h3>1) Discussion</h3> <p>Dozens of ideas for privacy-preserving technologies have been proposed by Chrome and others, for public discussion in forums such as the <a href="https://www.w3.org/">W3C</a> and <a href="https://github.com/">GitHub</a> . For example, more than 100 organizations are helping to refine <a href="https://developer.chrome.com/docs/privacy-sandbox/fledge/">FLEDGE</a>, a proposal for privacy-preserving remarketing.</p> <h3>2) Testing</h3> <p>Success at this stage depends on developers engaging in hands-on testing then sharing their learnings publicly. Yahoo! JAPAN's analysis of the <a href="https://developer.chrome.com/docs/privacy-sandbox/attribution-reporting/">Attribution Reporting API</a> and Criteo's machine learning competition for evaluating privacy concepts are examples we're grateful for. </p> <p>This kind of feedback is critical to getting solutions right. For instance, we're currently improving <a href="https://privacysandbox.com/proposals/floc">FLoC</a> &#8212; a proposal for anonymized interest groups &#8212; with insights from companies such as CafeMedia.</p> <h3>3) Scaled Adoption</h3> <p>Some Privacy Sandbox proposals are already live, such as <a href="https://web.dev/user-agent-client-hints/">User-Agent Client Hints</a> which are meant to replace the User-Agent (UA) string. We'll start to gradually reduce the granularity of information in the UA string in April 2022. We know implementing these changes take time, so companies will have the option to use the UA string as is through March 2023 via an origin trial.</p> <h2>Stepping up In-Browser Experiences </h2> <p>With <a href="https://web.dev/fugu-status/">Project Fugu</a>, we've been introducing APIs that elevate web apps so they can do anything native apps can. We've also been inspired by brands building more immersive web experiences with <a href="https://web.dev/progressive-web-apps/">Progressive Web Apps</a> (PWAs) and modern APIs.</p> <p>Take Adobe, a brand we've been partnering with for more than three years. Photoshop, Creative Cloud Spaces, and Creative Cloud Canvas are now in Public Beta and <a href="https://web.dev/ps-on-the-web/">available in browsers</a>&#8212;with more flagship apps to follow. This means creatives can view work, share feedback, and make basic edits without having to download or launch native apps. </p> <p>PWAs have given online video and web conferencing platforms an upgrade too. TikTok found a way to reach video lovers across all devices while YouTube Premium gives people the ability to watch videos offline on laptops and hybrid devices.</p><p>Meet drastically improved the audio and video quality in their PWA, and Kapwing focused on making it easy for users to edit videos collaboratively, anytime, anywhere. Zoom replaced their Chrome App with a PWA, and saw 16.9 million new users join web meetings, an increase of more than seven million users year over year.</p> <p>Developers who want to learn more, or get started with Progressive Web Apps can check out our new <a href="https://web.dev/learn/pwa/">Learn PWA</a> course on web.dev. Three modules were launched today, with many more coming.</p> <h2>Continuously Improving Your Web Experience</h2> <p>Measuring site performance is a key part of navigating browsers as they evolve, which is where <a href="https://web.dev/vitals/">Core Web Vitals</a> come in. Compared to a year ago, 20% more page visits in Chrome and 60% of the total visits in Chrome fully meet the recommended Core Web Vitals thresholds.</p> <p>Content management systems, website builders, e-commerce platforms, and JavaScript frameworks have helped push the Web Vitals initiative forward. As we shared in our <a href="https://datastudio.google.com/reporting/55bc8fad-44c2-4280-aa0b-5f3f0cd3d2be/page/M6ZPC">Core Web Vitals Technology Report</a>, sites built on many of these platforms are hitting Core Web Vitals out of the park: </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQ0_q90gAmJYGi77SiWEYIbJ4bdMBSsXBJEcMzKCEPMlM9eXrhq5qaUvPFKUKPe68tKR9ocEssLcS9oEoMb1bTYtebSvX2K-uaRZ9OSiu1qW09aKxFwVDO4gGi1cJFod737EmVIQN0KAnQ/s1424/copyofchrome-c--jg970ov54vc.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="878" data-original-width="1424" height="394" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQ0_q90gAmJYGi77SiWEYIbJ4bdMBSsXBJEcMzKCEPMlM9eXrhq5qaUvPFKUKPe68tKR9ocEssLcS9oEoMb1bTYtebSvX2K-uaRZ9OSiu1qW09aKxFwVDO4gGi1cJFod737EmVIQN0KAnQ/w640-h394/copyofchrome-c--jg970ov54vc.png" width="640" /></a></div><p>While this kind of progress is exciting, optimizing for Core Web Vitals can still be challenging. That's why we've been improving our tools to help developers better monitor, measure, and understand site performance. Some of these changes include:</p> <ul> <li>Updates in <a href="https://web.dev/whats-new-pagespeed-insights">PageSpeed Insights</a> which make the distinction between "field data" from user experiences and "lab data" from the Lighthouse report more clear.</li> </ul> <ul> <li>Capabilities in <a href="https://developers.google.com/web/tools/lighthouse">Lighthouse</a> to audit a complete <a href="https://web.dev/lighthouse-user-flows/">user flow</a> by loading additional pages and simulating scrolls and link clicks.</li> </ul> <ul> <li>Support for user flows, such as a checkout flow, in <a href="https://developer.chrome.com/docs/devtools/">DevTools</a> with a new <a href="https://goo.gle/devtools-recorder">Recorder panel</a> for exporting a recorded user journey to Puppeteer script.</li> </ul> <p>We're also experimenting with two new performance metrics: overall input responsiveness and scrolling and animation smoothness. We'd love to get your feedback, so take a spin through at <a href="https://web.dev/responsiveness">web.dev/responsiveness</a> and <a href="https://web.dev/smoothness">web.dev/smoothness</a>.</p> <h2>Expanding the Toolbox for Digital Interfaces </h2> <p>We've got developers and designers covered with tons of changes coming down the pipeline for UI styling and DevTools, including updates to responsive design. Developers can now customize user experiences in a component-driven architecture model, and we're calling this The New Responsive: </p> <div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqx19JX1EmPbxbYruKsSePKJKqfstwtG07VL6G72gbwFpAzLdvetzZfVKhgTF8IaZ73QcYkSVjosyjCwHQfMpgM1-ojQZ5145hAdbbhfGlSdZ538ClrHG33fOwMqfpdCcJOIiRedzy0p-9/s1580/copyofchrome-c--q1umlaeb369.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="864" data-original-width="1580" height="350" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqx19JX1EmPbxbYruKsSePKJKqfstwtG07VL6G72gbwFpAzLdvetzZfVKhgTF8IaZ73QcYkSVjosyjCwHQfMpgM1-ojQZ5145hAdbbhfGlSdZ538ClrHG33fOwMqfpdCcJOIiRedzy0p-9/w640-h350/copyofchrome-c--q1umlaeb369.png" width="640" /></a></div><br /><p><br /></p> <p>With the new container queries spec&#8212;available for testing behind a flag in <a href="https://www.google.com/chrome/canary/">Chrome Canary</a>&#8212;developers can access a parent element's width to make styling decisions for its children, nest container queries, and create named queries for easier access and organization.</p> <p>This is a huge shift for component-based development, so we've been providing new DevTools for debugging, styling, and visualizing CSS layouts. To make creating interfaces even easier, we also launched a collection of <a href="https://web.dev/patterns/">off-the-shelf UI patterns</a>.</p> <p>Developers who want to learn more can dive into free resources such as <a href="https://web.dev/learn/design/">Learn Responsive Design</a> on web.dev&#8212;a collaboration with Clearleft's Jeremy Keith&#8212;and six new modules in our <a href="https://web.dev/learn/css/">Learn CSS</a> course. There are also a few exciting CSS APIs in their first public working drafts, including: </p> <ul> <li><strong>Scroll-timeline</strong> for animating an element as people scroll (available via the experimental web platform features flag in Chrome Canary).</li> </ul> <ul> <li><strong>Size-adjust property</strong> for typography (available in Chromium and Firefox stable).</li> </ul> <ul> <li><strong>Accent-color</strong> for giving form controls a theme color (available in Chromium and Firefox stable).</li> </ul> <p>One feature we're really excited to build on is Dark Mode, especially because we found indications that dark themes use 11% less battery power than light themes for OLED screens. Stay tuned for a machine-learning-aided, auto-dark algorithm feature in an upcoming version of Chrome.</p> <h2>Buckling Down for the Road Ahead</h2> <p>Part of what makes the web so special is that it's an open, decentralized ecosystem. We encourage everyone to make the most of this by getting involved in shaping the web's future in places such as: </p> <ul> <li>The <a href="https://www.chromium.org/">Chromium open-source project</a></li> <li>Standards bodies such as the <a href="https://www.w3.org/">W3C</a> and <a href="https://whatwg.org/">WHATWG</a></li> <li><a href="https://web.dev/">web.dev</a> and our <a href="https://twitter.com/ChromiumDev?ref_src=twsrc%5Egoogle%7Ctwcamp%5Eserp%7Ctwgr%5Eauthor">@ChromiumDev</a> Twitter account</li> <li>Workshops, group learning lounges, and one-on-one office hours we'll be hosting over the next month</li> </ul> <p>We can't wait to see what the web looks like by next year's summit. Until then, check out our library of learning resources on the <a href="https://developer.chrome.com/devsummit/courses-and-content/">Chrome Dev Summit site</a> and the <a href="https://www.youtube.com/channel/UCnUYZLuoy1rq1aVMwx4aTzw">Chrome Developers YouTube channel</a>, and sign up for the <a href="https://web.dev/newsletter/">web.dev newsletter</a>.</p> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <span class="post-author">By Paul Kinlan, Lead for Chrome Developer Relations</span> <p>The big day is finally here. Today, at Chrome Dev Summit 2021 we shared some of the highlights of what we've been working on &#8212; the latest product updates, vision for the web's future and examples of best-in-class web experiences. Over the past year, we've also had a lot of feedback that you want to spend more time learning from and working with the Chrome team and other industry experts. I'm excited to share with you that <a href="https://developer.chrome.com/devsummit/schedule/">we've opened up a lot of spaces for 1:1 office hours, workshops and learning lounges</a> to give you more opportunity to connect with the Chrome team.</p> <p>It's been a busy year for us all and with the continued shift of people moving more of their lives online, it has been more important than ever for us to <a href="https://web.dev/compat2021-midyear/">continue investing in Web Compat</a>, and we've been amazed to see the <a href="https://wpt.fyi/compat2021?feature=summary">improvements in compatibility across the board</a> that is helping to make it easier for you to build sites that work across all browsers for everyone who uses the web.</p> <p>We've also got a number of important updates to core topics that are important to every developer:</p> <ul> <li>An update on how we're helping to shift the web towards more privacy-safe technologies and give you more visibility into that process.</li> <li>A showcase on how many major companies have bet on the web and brough advanced app-like experiences to anyone who can use a browser.</li> <li>An update on Core Web Vitals and some new tools that will make it easier for you to measure your sites.</li> <li>A dive into the "New Responsive" with highlights of new tools and capabilities for designers that make it easier than ever to build experiences your users love.</li> </ul> <p>This post is an overview of the latest updates from this year's Chrome Dev Summit keynote. </p><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="331" src="https://www.youtube.com/embed/n57U2_-3NLQ" width="486" youtube-src-id="n57U2_-3NLQ"></iframe></div><br /> <h2 style="text-align: left;">Paving a Path Toward a More Secure Web</h2> <p>The <a href="https://privacysandbox.com/">Privacy Sandbox</a> continues to be a cornerstone of our ongoing efforts to collaboratively build privacy-preserving technologies for a healthy web. Our <a href="https://privacysandbox.com/timeline/">development timeline</a>, which we'll update monthly, shares when developers and advertisers can expect these technologies to be ready for testing and scaled adoption.<br /> This timeline reflects three developmental phases for Privacy Sandbox proposals:</p> <h3>1) Discussion</h3> <p>Dozens of ideas for privacy-preserving technologies have been proposed by Chrome and others, for public discussion in forums such as the <a href="https://www.w3.org/">W3C</a> and <a href="https://github.com/">GitHub</a> . For example, more than 100 organizations are helping to refine <a href="https://developer.chrome.com/docs/privacy-sandbox/fledge/">FLEDGE</a>, a proposal for privacy-preserving remarketing.</p> <h3>2) Testing</h3> <p>Success at this stage depends on developers engaging in hands-on testing then sharing their learnings publicly. Yahoo! JAPAN's analysis of the <a href="https://developer.chrome.com/docs/privacy-sandbox/attribution-reporting/">Attribution Reporting API</a> and Criteo's machine learning competition for evaluating privacy concepts are examples we're grateful for. </p> <p>This kind of feedback is critical to getting solutions right. For instance, we're currently improving <a href="https://privacysandbox.com/proposals/floc">FLoC</a> &#8212; a proposal for anonymized interest groups &#8212; with insights from companies such as CafeMedia.</p> <h3>3) Scaled Adoption</h3> <p>Some Privacy Sandbox proposals are already live, such as <a href="https://web.dev/user-agent-client-hints/">User-Agent Client Hints</a> which are meant to replace the User-Agent (UA) string. We'll start to gradually reduce the granularity of information in the UA string in April 2022. We know implementing these changes take time, so companies will have the option to use the UA string as is through March 2023 via an origin trial.</p> <h2>Stepping up In-Browser Experiences </h2> <p>With <a href="https://web.dev/fugu-status/">Project Fugu</a>, we've been introducing APIs that elevate web apps so they can do anything native apps can. We've also been inspired by brands building more immersive web experiences with <a href="https://web.dev/progressive-web-apps/">Progressive Web Apps</a> (PWAs) and modern APIs.</p> <p>Take Adobe, a brand we've been partnering with for more than three years. Photoshop, Creative Cloud Spaces, and Creative Cloud Canvas are now in Public Beta and <a href="https://web.dev/ps-on-the-web/">available in browsers</a>&#8212;with more flagship apps to follow. This means creatives can view work, share feedback, and make basic edits without having to download or launch native apps. </p> <p>PWAs have given online video and web conferencing platforms an upgrade too. TikTok found a way to reach video lovers across all devices while YouTube Premium gives people the ability to watch videos offline on laptops and hybrid devices.</p><p>Meet drastically improved the audio and video quality in their PWA, and Kapwing focused on making it easy for users to edit videos collaboratively, anytime, anywhere. Zoom replaced their Chrome App with a PWA, and saw 16.9 million new users join web meetings, an increase of more than seven million users year over year.</p> <p>Developers who want to learn more, or get started with Progressive Web Apps can check out our new <a href="https://web.dev/learn/pwa/">Learn PWA</a> course on web.dev. Three modules were launched today, with many more coming.</p> <h2>Continuously Improving Your Web Experience</h2> <p>Measuring site performance is a key part of navigating browsers as they evolve, which is where <a href="https://web.dev/vitals/">Core Web Vitals</a> come in. Compared to a year ago, 20% more page visits in Chrome and 60% of the total visits in Chrome fully meet the recommended Core Web Vitals thresholds.</p> <p>Content management systems, website builders, e-commerce platforms, and JavaScript frameworks have helped push the Web Vitals initiative forward. As we shared in our <a href="https://datastudio.google.com/reporting/55bc8fad-44c2-4280-aa0b-5f3f0cd3d2be/page/M6ZPC">Core Web Vitals Technology Report</a>, sites built on many of these platforms are hitting Core Web Vitals out of the park: </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQ0_q90gAmJYGi77SiWEYIbJ4bdMBSsXBJEcMzKCEPMlM9eXrhq5qaUvPFKUKPe68tKR9ocEssLcS9oEoMb1bTYtebSvX2K-uaRZ9OSiu1qW09aKxFwVDO4gGi1cJFod737EmVIQN0KAnQ/s1424/copyofchrome-c--jg970ov54vc.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="878" data-original-width="1424" height="394" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQ0_q90gAmJYGi77SiWEYIbJ4bdMBSsXBJEcMzKCEPMlM9eXrhq5qaUvPFKUKPe68tKR9ocEssLcS9oEoMb1bTYtebSvX2K-uaRZ9OSiu1qW09aKxFwVDO4gGi1cJFod737EmVIQN0KAnQ/w640-h394/copyofchrome-c--jg970ov54vc.png" width="640" /></a></div><p>While this kind of progress is exciting, optimizing for Core Web Vitals can still be challenging. That's why we've been improving our tools to help developers better monitor, measure, and understand site performance. Some of these changes include:</p> <ul> <li>Updates in <a href="https://web.dev/whats-new-pagespeed-insights">PageSpeed Insights</a> which make the distinction between "field data" from user experiences and "lab data" from the Lighthouse report more clear.</li> </ul> <ul> <li>Capabilities in <a href="https://developers.google.com/web/tools/lighthouse">Lighthouse</a> to audit a complete <a href="https://web.dev/lighthouse-user-flows/">user flow</a> by loading additional pages and simulating scrolls and link clicks.</li> </ul> <ul> <li>Support for user flows, such as a checkout flow, in <a href="https://developer.chrome.com/docs/devtools/">DevTools</a> with a new <a href="https://goo.gle/devtools-recorder">Recorder panel</a> for exporting a recorded user journey to Puppeteer script.</li> </ul> <p>We're also experimenting with two new performance metrics: overall input responsiveness and scrolling and animation smoothness. We'd love to get your feedback, so take a spin through at <a href="https://web.dev/responsiveness">web.dev/responsiveness</a> and <a href="https://web.dev/smoothness">web.dev/smoothness</a>.</p> <h2>Expanding the Toolbox for Digital Interfaces </h2> <p>We've got developers and designers covered with tons of changes coming down the pipeline for UI styling and DevTools, including updates to responsive design. Developers can now customize user experiences in a component-driven architecture model, and we're calling this The New Responsive: </p> <div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqx19JX1EmPbxbYruKsSePKJKqfstwtG07VL6G72gbwFpAzLdvetzZfVKhgTF8IaZ73QcYkSVjosyjCwHQfMpgM1-ojQZ5145hAdbbhfGlSdZ538ClrHG33fOwMqfpdCcJOIiRedzy0p-9/s1580/copyofchrome-c--q1umlaeb369.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="864" data-original-width="1580" height="350" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqx19JX1EmPbxbYruKsSePKJKqfstwtG07VL6G72gbwFpAzLdvetzZfVKhgTF8IaZ73QcYkSVjosyjCwHQfMpgM1-ojQZ5145hAdbbhfGlSdZ538ClrHG33fOwMqfpdCcJOIiRedzy0p-9/w640-h350/copyofchrome-c--q1umlaeb369.png" width="640" /></a></div><br /><p><br /></p> <p>With the new container queries spec&#8212;available for testing behind a flag in <a href="https://www.google.com/chrome/canary/">Chrome Canary</a>&#8212;developers can access a parent element's width to make styling decisions for its children, nest container queries, and create named queries for easier access and organization.</p> <p>This is a huge shift for component-based development, so we've been providing new DevTools for debugging, styling, and visualizing CSS layouts. To make creating interfaces even easier, we also launched a collection of <a href="https://web.dev/patterns/">off-the-shelf UI patterns</a>.</p> <p>Developers who want to learn more can dive into free resources such as <a href="https://web.dev/learn/design/">Learn Responsive Design</a> on web.dev&#8212;a collaboration with Clearleft's Jeremy Keith&#8212;and six new modules in our <a href="https://web.dev/learn/css/">Learn CSS</a> course. There are also a few exciting CSS APIs in their first public working drafts, including: </p> <ul> <li><strong>Scroll-timeline</strong> for animating an element as people scroll (available via the experimental web platform features flag in Chrome Canary).</li> </ul> <ul> <li><strong>Size-adjust property</strong> for typography (available in Chromium and Firefox stable).</li> </ul> <ul> <li><strong>Accent-color</strong> for giving form controls a theme color (available in Chromium and Firefox stable).</li> </ul> <p>One feature we're really excited to build on is Dark Mode, especially because we found indications that dark themes use 11% less battery power than light themes for OLED screens. Stay tuned for a machine-learning-aided, auto-dark algorithm feature in an upcoming version of Chrome.</p> <h2>Buckling Down for the Road Ahead</h2> <p>Part of what makes the web so special is that it's an open, decentralized ecosystem. We encourage everyone to make the most of this by getting involved in shaping the web's future in places such as: </p> <ul> <li>The <a href="https://www.chromium.org/">Chromium open-source project</a></li> <li>Standards bodies such as the <a href="https://www.w3.org/">W3C</a> and <a href="https://whatwg.org/">WHATWG</a></li> <li><a href="https://web.dev/">web.dev</a> and our <a href="https://twitter.com/ChromiumDev?ref_src=twsrc%5Egoogle%7Ctwcamp%5Eserp%7Ctwgr%5Eauthor">@ChromiumDev</a> Twitter account</li> <li>Workshops, group learning lounges, and one-on-one office hours we'll be hosting over the next month</li> </ul> <p>We can't wait to see what the web looks like by next year's summit. Until then, check out our library of learning resources on the <a href="https://developer.chrome.com/devsummit/courses-and-content/">Chrome Dev Summit site</a> and the <a href="https://www.youtube.com/channel/UCnUYZLuoy1rq1aVMwx4aTzw">Chrome Developers YouTube channel</a>, and sign up for the <a href="https://web.dev/newsletter/">web.dev newsletter</a>.</p> <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 Dev Summit 2021: Moving toward a more powerful and private web&url=https://blog.chromium.org/2021/11/chrome-dev-summit-2021-moving-toward.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/2021/11/chrome-dev-summit-2021-moving-toward.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/2021/11/chrome-dev-summit-2021-moving-toward.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='8692686698337239782' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2021/11/run-on-os-login.html' itemprop='url' title='Run on OS Login'> Run on OS Login </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Tuesday, November 2, 2021 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <p>Users want frequently used applications such as Email, Chat, and other productivity apps to automatically start when they log in to their devices. Auto-starting these apps at login streamlines the user experience as users don't have to manually start apps after logging into their devices. <br /> Windows, Mac, and Linux devices allow users to configure native apps to be launched automatically on startup. In Chrome 91, we introduced the Run on OS Login feature. With the launch of this feature, users can now configure desktop web apps to launch automatically when they log-in to the device on Windows, Mac, and Linux devices. <em>Installed apps will not be permitted to automatically enable themselves to run when the user logs in. A manual user gesture will always be required. </em><br /> To configure apps to run on OS login, open Chrome browser. Navigate to chrome://apps or click the &#8216;Apps' icon in your bookmark bar (example below). </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRO8nghsrfQxLQ7PDh-mlBu5_pUYBJGjyPXgviVrHihnO2pwdj4FQZixbS6KY8MZ02_0_YGsLdLUeOySLkb_D7EQh3sZgw-ERoGu9iTwTqTSNOKns5dQUte-PaC3B9xp_bTvC4D94zN1A2/s66/copyofrunonosl--dkwpvkjdw5v.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="27" data-original-width="66" height="27" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRO8nghsrfQxLQ7PDh-mlBu5_pUYBJGjyPXgviVrHihnO2pwdj4FQZixbS6KY8MZ02_0_YGsLdLUeOySLkb_D7EQh3sZgw-ERoGu9iTwTqTSNOKns5dQUte-PaC3B9xp_bTvC4D94zN1A2/s0/copyofrunonosl--dkwpvkjdw5v.png" width="66" /></a></div><p>To configure an app to start at login, first right click on it. From the context menu, select &#8216;Start app when you sign in' and you are all set. Next time when you log in to your device, the app will automatically launch on its own. To disable this feature for an app, navigate to <span style="font-family: courier; font-size: x-small;">chrome://apps</span>. Right click on the app to bring up the context menu and deselect the option, &#8216;Start app when you sign in'.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS6rK1xAnqVGJDjAJ_Br7oY8AkNljxKCob4jTuS_6zU1FYbFj6MNlGHGooJvzAkI5jkH7sRqC8wfyOMiRFKZiGAmeMRfprvRDK8wFpxBHnqDGOTJaBGDlvYamHSkvgIEakPgRXY_aV6svF/s1057/copyofrunonosl--ukb91y8rh2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="799" data-original-width="1057" height="484" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS6rK1xAnqVGJDjAJ_Br7oY8AkNljxKCob4jTuS_6zU1FYbFj6MNlGHGooJvzAkI5jkH7sRqC8wfyOMiRFKZiGAmeMRfprvRDK8wFpxBHnqDGOTJaBGDlvYamHSkvgIEakPgRXY_aV6svF/w640-h484/copyofrunonosl--ukb91y8rh2.png" width="640" /></a></div><p>Apps launched through Run on OS Login are launched only after the device is running. &#8216;Run on OS Login' is a browser only feature and doesn't expose any launch source information to app developers.</p><p> We're continuously improving the web platform to provide safe, low friction ways for users to get their day-to-day tasks done. Support for running installed web apps on OS login is a small but significant step to simplifying the startup routine for users that want apps like chat, email, or calendar clients to start as soon as they turn on their computer. As always, we're looking forward to your <a href="https://forms.gle/JtHPkor6Z5dP87RU7">feedback</a>. Your input will help us prioritize next steps!</p> <div><span class="post-author"><br /></span></div><span class="post-author">Posted by Pratyush Sinha </span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <p>Users want frequently used applications such as Email, Chat, and other productivity apps to automatically start when they log in to their devices. Auto-starting these apps at login streamlines the user experience as users don't have to manually start apps after logging into their devices. <br /> Windows, Mac, and Linux devices allow users to configure native apps to be launched automatically on startup. In Chrome 91, we introduced the Run on OS Login feature. With the launch of this feature, users can now configure desktop web apps to launch automatically when they log-in to the device on Windows, Mac, and Linux devices. <em>Installed apps will not be permitted to automatically enable themselves to run when the user logs in. A manual user gesture will always be required. </em><br /> To configure apps to run on OS login, open Chrome browser. Navigate to chrome://apps or click the &#8216;Apps' icon in your bookmark bar (example below). </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRO8nghsrfQxLQ7PDh-mlBu5_pUYBJGjyPXgviVrHihnO2pwdj4FQZixbS6KY8MZ02_0_YGsLdLUeOySLkb_D7EQh3sZgw-ERoGu9iTwTqTSNOKns5dQUte-PaC3B9xp_bTvC4D94zN1A2/s66/copyofrunonosl--dkwpvkjdw5v.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="27" data-original-width="66" height="27" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRO8nghsrfQxLQ7PDh-mlBu5_pUYBJGjyPXgviVrHihnO2pwdj4FQZixbS6KY8MZ02_0_YGsLdLUeOySLkb_D7EQh3sZgw-ERoGu9iTwTqTSNOKns5dQUte-PaC3B9xp_bTvC4D94zN1A2/s0/copyofrunonosl--dkwpvkjdw5v.png" width="66" /></a></div><p>To configure an app to start at login, first right click on it. From the context menu, select &#8216;Start app when you sign in' and you are all set. Next time when you log in to your device, the app will automatically launch on its own. To disable this feature for an app, navigate to <span style="font-family: courier; font-size: x-small;">chrome://apps</span>. Right click on the app to bring up the context menu and deselect the option, &#8216;Start app when you sign in'.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS6rK1xAnqVGJDjAJ_Br7oY8AkNljxKCob4jTuS_6zU1FYbFj6MNlGHGooJvzAkI5jkH7sRqC8wfyOMiRFKZiGAmeMRfprvRDK8wFpxBHnqDGOTJaBGDlvYamHSkvgIEakPgRXY_aV6svF/s1057/copyofrunonosl--ukb91y8rh2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="799" data-original-width="1057" height="484" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS6rK1xAnqVGJDjAJ_Br7oY8AkNljxKCob4jTuS_6zU1FYbFj6MNlGHGooJvzAkI5jkH7sRqC8wfyOMiRFKZiGAmeMRfprvRDK8wFpxBHnqDGOTJaBGDlvYamHSkvgIEakPgRXY_aV6svF/w640-h484/copyofrunonosl--ukb91y8rh2.png" width="640" /></a></div><p>Apps launched through Run on OS Login are launched only after the device is running. &#8216;Run on OS Login' is a browser only feature and doesn't expose any launch source information to app developers.</p><p> We're continuously improving the web platform to provide safe, low friction ways for users to get their day-to-day tasks done. Support for running installed web apps on OS login is a small but significant step to simplifying the startup routine for users that want apps like chat, email, or calendar clients to start as soon as they turn on their computer. As always, we're looking forward to your <a href="https://forms.gle/JtHPkor6Z5dP87RU7">feedback</a>. Your input will help us prioritize next steps!</p> <div><span class="post-author"><br /></span></div><span class="post-author">Posted by Pratyush Sinha </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:Run on OS Login&url=https://blog.chromium.org/2021/11/run-on-os-login.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/2021/11/run-on-os-login.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/2021/11/run-on-os-login.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='4655915224338266183' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2021/11/searching-browsing-shutdown-chrome-performance-improvements.html' itemprop='url' title='Searching, browsing, and shutdown Chrome performance improvements'> Searching, browsing, and shutdown Chrome performance improvements </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Monday, November 1, 2021 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <i><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEla8ATT6YFRR-WRWz6rYikJTRguAKKB5LKefpCd3XIRnfS2JTtRnjFDyJfjsqj890eM5N0K4r7EDsju4WJqSCE8U1zCK4d2ScapEh9KR6Z9hCEFgOaL5yH6vYefoEgTxR7P0coztCpt4R/s1999/image1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="830" data-original-width="1999" height="292" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEla8ATT6YFRR-WRWz6rYikJTRguAKKB5LKefpCd3XIRnfS2JTtRnjFDyJfjsqj890eM5N0K4r7EDsju4WJqSCE8U1zCK4d2ScapEh9KR6Z9hCEFgOaL5yH6vYefoEgTxR7P0coztCpt4R/w702-h292/image1.jpg" width="702" /></a></div><div><i><br /></i></div>Chrome has long-term investments in performance improvement across many projects and we are pleased to share improvements across speed, memory, and unexpected hangs in today&#8217;s <a href="https://blog.chromium.org/search/label/the%20fast%20and%20the%20curious">The Fast and the Curious</a> series post. One in six searches is now as fast as a blink of an eye, Chrome OS browsing now uses up to 20% less memory <a href="https://blog.chromium.org/2021/04/efficient-and-safe-allocations-everywhere.html">thanks to our PartitionAlloc investment</a>, and we&#8217;ve resolved some thorny Chrome OS and Windows shutdown experiences.</i><h1 style="text-align: left;">Omnibox</h1><div>You&#8217;ve probably noticed that potential queries are suggested to you as you type when you&#8217;re searching the web using Chrome&#8217;s omnibox (as long as the &#8220;Autocomplete searches and URLs&#8221; feature is turned on in Chrome settings.) This makes searching for information faster and easier, as you don&#8217;t have to type in the entire search query -- once you&#8217;ve entered enough text for the suggestion to be the one you want, you can quickly select it. <br /><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmBrL8llGFT3x4B9VUFCYUnwfs1C1Ul8NUYTDlrgPpl5l2pJ-5l_ifMq8CIBg94GpnZWf-RvYb96x4gouOgIHt1qTADzuV-zmFSUul3FRIiqOPvReH-SCgzc9jJA0-iJZ2Lak-DLlugeUm/s1999/image2.png"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmBrL8llGFT3x4B9VUFCYUnwfs1C1Ul8NUYTDlrgPpl5l2pJ-5l_ifMq8CIBg94GpnZWf-RvYb96x4gouOgIHt1qTADzuV-zmFSUul3FRIiqOPvReH-SCgzc9jJA0-iJZ2Lak-DLlugeUm/w654-h439/image2.png" /></a><br /><br /><br />Searching in Chrome is now even faster, as search results are prefetched if a suggested query is very likely to be selected. This means that you see the search results more quickly, as they&#8217;ve been fetched from the web server before you even select the query. In fact, our experiments found that search results are now 4X more likely to be shown within 500 ms!<br /><br />Currently, this only happens if Google Search is your default search engine. However, other search providers can trigger this feature by adding information to the query suggestions sent from their servers to Chrome, as described in this <a href="https://sites.google.com/a/chromium.org/dev/developers/design-documents/omnibox-prefetch-for-default-search-engines">article</a>.<br /><h1 style="text-align: left;">Chrome OS PartitionAlloc</h1></div><div>Chrome&#8217;s new memory allocator, <a href="https://blog.chromium.org/2021/04/efficient-and-safe-allocations-everywhere.html">PartitionAlloc</a>, rolled out on Android and Windows in M89, bringing improved memory usage [up to 22% savings] and performance [up to 9% faster responsiveness]. Since then, we have also implemented PartitionAlloc on Linux in M92 and Chrome OS in M93. We are now pleased to announce that M93 field data from Chrome OS shows a total memory footprint reduction of 15% in addition to a 20% browser process memory reduction, improving the Chromebook browsing experience for both single and multi-tabs.<br /><br /><h1 style="text-align: left;">Resolving the #1 shutdown hang</h1></div><div>Often software engineers add a cache to a system with the goal of improving performance. But a frequent corollary of caching is that the cache may introduce other problems (code complexity, stability, memory consumption, data consistency), and may even make performance worse. In this case, a local cache was added years ago to Chrome's history system with the goal of making startup faster. The premise at the time, which seemed to bear out in lab testing, was that caching Chrome's internal in-memory history index would be faster than reindexing the history at each startup.<br /><br />Thanks to our continuing systematic investigation into real-world performance using crash data in conjunction with anonymized performance metrics, we uncovered that not only did this cache add code complexity and unnecessary memory usage, but it was also our top contributor to shutdown hangs in the browser. This is because on some OSes, background priority threads can be starved of I/O indefinitely while there is any other I/O happening elsewhere on the system. Moreover, the performance benefits to our users were minimal, based on analysis of field data. We've now removed the cache and resolved our top shutdown hang. This was a great illustration of the principle that caching is not always the answer!<br /><br />Stay tuned for many more performance improvements to come!<br /><br />Posted by Yana Yushkina, Product Manager, Chrome Browser<br /><br /><i>Data source for all statistics: <a href="https://www.google.com/chrome/privacy/whitepaper.html#usagestats">Real-world data</a>&nbsp;anonymously aggregated from Chrome clients.</i></div><div><br /></div><br /> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <i><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEla8ATT6YFRR-WRWz6rYikJTRguAKKB5LKefpCd3XIRnfS2JTtRnjFDyJfjsqj890eM5N0K4r7EDsju4WJqSCE8U1zCK4d2ScapEh9KR6Z9hCEFgOaL5yH6vYefoEgTxR7P0coztCpt4R/s1999/image1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="830" data-original-width="1999" height="292" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEla8ATT6YFRR-WRWz6rYikJTRguAKKB5LKefpCd3XIRnfS2JTtRnjFDyJfjsqj890eM5N0K4r7EDsju4WJqSCE8U1zCK4d2ScapEh9KR6Z9hCEFgOaL5yH6vYefoEgTxR7P0coztCpt4R/w702-h292/image1.jpg" width="702" /></a></div><div><i><br /></i></div>Chrome has long-term investments in performance improvement across many projects and we are pleased to share improvements across speed, memory, and unexpected hangs in today&#8217;s <a href="https://blog.chromium.org/search/label/the%20fast%20and%20the%20curious">The Fast and the Curious</a> series post. One in six searches is now as fast as a blink of an eye, Chrome OS browsing now uses up to 20% less memory <a href="https://blog.chromium.org/2021/04/efficient-and-safe-allocations-everywhere.html">thanks to our PartitionAlloc investment</a>, and we&#8217;ve resolved some thorny Chrome OS and Windows shutdown experiences.</i><h1 style="text-align: left;">Omnibox</h1><div>You&#8217;ve probably noticed that potential queries are suggested to you as you type when you&#8217;re searching the web using Chrome&#8217;s omnibox (as long as the &#8220;Autocomplete searches and URLs&#8221; feature is turned on in Chrome settings.) This makes searching for information faster and easier, as you don&#8217;t have to type in the entire search query -- once you&#8217;ve entered enough text for the suggestion to be the one you want, you can quickly select it. <br /><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmBrL8llGFT3x4B9VUFCYUnwfs1C1Ul8NUYTDlrgPpl5l2pJ-5l_ifMq8CIBg94GpnZWf-RvYb96x4gouOgIHt1qTADzuV-zmFSUul3FRIiqOPvReH-SCgzc9jJA0-iJZ2Lak-DLlugeUm/s1999/image2.png"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmBrL8llGFT3x4B9VUFCYUnwfs1C1Ul8NUYTDlrgPpl5l2pJ-5l_ifMq8CIBg94GpnZWf-RvYb96x4gouOgIHt1qTADzuV-zmFSUul3FRIiqOPvReH-SCgzc9jJA0-iJZ2Lak-DLlugeUm/w654-h439/image2.png" /></a><br /><br /><br />Searching in Chrome is now even faster, as search results are prefetched if a suggested query is very likely to be selected. This means that you see the search results more quickly, as they&#8217;ve been fetched from the web server before you even select the query. In fact, our experiments found that search results are now 4X more likely to be shown within 500 ms!<br /><br />Currently, this only happens if Google Search is your default search engine. However, other search providers can trigger this feature by adding information to the query suggestions sent from their servers to Chrome, as described in this <a href="https://sites.google.com/a/chromium.org/dev/developers/design-documents/omnibox-prefetch-for-default-search-engines">article</a>.<br /><h1 style="text-align: left;">Chrome OS PartitionAlloc</h1></div><div>Chrome&#8217;s new memory allocator, <a href="https://blog.chromium.org/2021/04/efficient-and-safe-allocations-everywhere.html">PartitionAlloc</a>, rolled out on Android and Windows in M89, bringing improved memory usage [up to 22% savings] and performance [up to 9% faster responsiveness]. Since then, we have also implemented PartitionAlloc on Linux in M92 and Chrome OS in M93. We are now pleased to announce that M93 field data from Chrome OS shows a total memory footprint reduction of 15% in addition to a 20% browser process memory reduction, improving the Chromebook browsing experience for both single and multi-tabs.<br /><br /><h1 style="text-align: left;">Resolving the #1 shutdown hang</h1></div><div>Often software engineers add a cache to a system with the goal of improving performance. But a frequent corollary of caching is that the cache may introduce other problems (code complexity, stability, memory consumption, data consistency), and may even make performance worse. In this case, a local cache was added years ago to Chrome's history system with the goal of making startup faster. The premise at the time, which seemed to bear out in lab testing, was that caching Chrome's internal in-memory history index would be faster than reindexing the history at each startup.<br /><br />Thanks to our continuing systematic investigation into real-world performance using crash data in conjunction with anonymized performance metrics, we uncovered that not only did this cache add code complexity and unnecessary memory usage, but it was also our top contributor to shutdown hangs in the browser. This is because on some OSes, background priority threads can be starved of I/O indefinitely while there is any other I/O happening elsewhere on the system. Moreover, the performance benefits to our users were minimal, based on analysis of field data. We've now removed the cache and resolved our top shutdown hang. This was a great illustration of the principle that caching is not always the answer!<br /><br />Stay tuned for many more performance improvements to come!<br /><br />Posted by Yana Yushkina, Product Manager, Chrome Browser<br /><br /><i>Data source for all statistics: <a href="https://www.google.com/chrome/privacy/whitepaper.html#usagestats">Real-world data</a>&nbsp;anonymously aggregated from Chrome clients.</i></div><div><br /></div><br /> <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:Searching, browsing, and shutdown Chrome performance improvements&url=https://blog.chromium.org/2021/11/searching-browsing-shutdown-chrome-performance-improvements.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/2021/11/searching-browsing-shutdown-chrome-performance-improvements.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/2021/11/searching-browsing-shutdown-chrome-performance-improvements.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> <span class='labels-caption'> Labels: </span> <span class='labels'> <a class='label' href='https://blog.chromium.org/search/label/performance' rel='tag'> performance </a> , <a class='label' href='https://blog.chromium.org/search/label/the%20fast%20and%20the%20curious' rel='tag'> the fast and the curious </a> </span> </div> </div> </div> <div class='post' data-id='7421677691035745159' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2021/10/chrome-96-beta-conditional-focus.html' itemprop='url' title='Chrome 96 Beta: Conditional Focus, Priority Hints, and More'> Chrome 96 Beta: Conditional Focus, Priority Hints, and More </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Thursday, October 21, 2021 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <p>Unless otherwise noted, changes described below apply to the newest Chrome beta channel release for Android, Chrome OS, Linux, macOS, and Windows. Learn more about the features listed here through the provided links or from the list on <a href="https://www.chromestatus.com/features#milestone%3D76">ChromeStatus.com</a>. Chrome 96 is beta as of October 21, 2021.</p> <h2>Preparing for a Three Digit Version Number</h2> <p>Next year, Chrome will release version 100. This will add a digit to the version number reported in Chrome's user agent string. To help site owners test for the new string, Chrome 96 introduces a runtime flag that causes Chrome to return '100' in its user agent string. This new flag called <code>chrome://flags/#force-major-version-to-100</code> is available from Chrome 96 onward.</p> <h2>Origin Trials</h2> <p>This version of Chrome introduces the origin trials described below. Origin trials allow you to try new features and give feedback on usability, practicality, and effectiveness to the web standards community. To register for any of the origin trials currently supported in Chrome, including the ones described below, visit the <a href="https://developers.chrome.com/origintrials/#/trials/active">Chrome Origin Trials dashboard</a>. To learn more about origin trials in Chrome, visit the <a href="https://web.dev/origin-trials/">Origin Trials Guide for Web Developers</a>. Microsoft Edge runs its own origin trials separate from Chrome. To learn more, see the <a href="https://developer.microsoft.com/en-us/microsoft-edge/origin-trials/">Microsoft Edge Origin Trials Developer Console</a>. </p> <h3>New Origin Trials</h3> <h4>Conditional Focus</h4> <p>Applications that capture other windows or tabs currently have no way to control whether the calling item or the captured item gets focus. (Think of a presentation feature in a video conference app.) <a href="https://developer.chrome.com/origintrials/#/view_trial/4329085141809889281">Chrome 96 makes this possible</a> with a subclass of <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack">MediaStreamTrack</a></code> called <code>FocusableMediaStreamTrack</code>, which supports a new <code>focus()</code> method. Consider the following code:</p> <pre>stream = await navigator.mediaDevices.getDisplayMedia(); let [track] = stream.getVideoTracks(); </pre> <p>Where formerly, <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaStream/getVideoTracks">getVideoTracks()</a></code> would return an array of <code>MediaStreamTrack</code> objects, it now returns <code>FocusableMediaStreamTrack</code> objects. (Note that this is expected to change to <code>BrowserCaptureMediaStreamTrack</code> in Chrome 97. At the time of this writing, Canary already does this.)</p> <p>To determine which display media gets focus, the next line of this code would call <code>track.focus()</code> with either <code>"focus-captured-surface"</code> to focus the newly captured window or tab, or with <code>"no-focus-change"</code> to keep the focus with the calling window. On Chrome 96 or later, you can step through our <a href="https://eladalon1983.github.io/conditional-focus/demo/">demo code</a> to see this in action. </p> <h4>Priority Hints</h4> <p>Priority Hints <a href="https://web.dev/priority-hints/">introduces a developer-set <code>"importance"</code> attribute</a> to influence the computed priority of a resource. Supported importance values are <code>"auto"</code>, <code>"low"</code>, and <code>"high"</code>. Priority Hints indicate a resource's relative importance to the browser, allowing more control over the order resources are loaded. Many factors influence a resource's priority in browsers including type, visibility, and preload status of a resource.</p> <h2>Other Features in this Release</h2> <h3>Allow Simple Range Header Values Without Preflight</h3> <p>Requests with simple range headers<a href="https://www.chromestatus.com/feature/5652396366626816"> can now be sent</a> without <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#preflighted_requests">a preflight request</a>. CORS requests can use the Range header in limited ways (only one valid range) without triggering a preflight request.</p> <h3>Back-forward Cache on Desktop</h3> <p>The <a href="https://www.chromestatus.com/feature/5815270035685376">back-forward cache</a> stores pages to allow for instant navigations to previously-visited pages after cross-site navigations.</p> <h3>Cross-Origin-Embedder-Policy: credentialless</h3> <p><code>Cross-Origin-Embedder-Policy</code> has <a href="https://www.chromestatus.com/feature/4918234241302528">a new <code>credentialless</code> option</a> that causes cross-origin <code>no-cors</code> requests to omit credentials (cookies, client certificates, etc.). Similarly to <code>COEP:require-corp</code>, it can enable cross-origin isolation.</p> <p>Sites that want to continue using <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer">SharedArrayBuffer</a> must opt-in to cross-origin isolation. Doing so using <code>COEP: require-corp</code> is difficult to deploy at scale and requires all subresources to explicitly opt-in. This is fine for some sites, but creates dependency problems for sites that gather content from users (Google Earth, social media generally, forums, etc).</p> <h3>CSS</h3> <h4>:autofill Pseudo Class</h4> <p>The new <a href="https://www.chromestatus.com/feature/5592445322526720"><code>autofill</code> pseudo class</a> enables styling autofilled form elements. This is a standardization of the <code>:-webkit-autofill</code> pseudo class which is already supported in WebKit. Firefox supports the standard version.</p> <h4>Disable Propagation of Body Style to Viewport when Contained</h4> <p>Some properties like writing-mode, direction, and backgrounds are propagated from body to the viewport. To avoid infinite loops for CSS Container Queries, the<a href="https://www.chromestatus.com/feature/5663240823504896"> spec and implementation were changed</a> to not propagate those properties when containment is applied to HTML or BODY.</p> <h4>font-synthesis Property</h4> <p>The <a href="https://www.chromestatus.com/feature/5640605355999232"><code>font-synthesis</code> CSS property</a> controls whether user agents are allowed to synthesize oblique, bold, and small-caps font faces when a font family lacks faces.</p> <h3>EME MediaKeySession Closed Reason</h3> <p>The <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaKeySession/closed">MediaKeySession.closed</a></code> property <a href="https://www.chromestatus.com/feature/5632124143009792">now uses an enum to indicate the reason</a> the <code>MediaKeySession</code> object closed. The closed property returns a Promise that resolves when the session closes. Where previously, the Promise simply resolved, it <a href="https://www.google.com/url?q=https://googlechrome.github.io/samples/media/key-session-closed-reason.html&amp;sa=D&amp;source=docs&amp;ust=1634547430725000&amp;usg=AOvVaw3cXtJIna_rtEkWm9LLzyft">now resolves with a string</a> indicating the reason for closing. The returned string will be one of <code>"internal-error"</code>, <code>"closed-by-application"</code>, <code>"release-acknowledged"</code>, <code>"hardware-context-reset"</code>, or <code>"resource-evicted"</code>.</p> <h3>HTTP to HTTPS Redirect for HTTPS DNS Records</h3> <p>Chrome will always <a href="https://www.chromestatus.com/feature/5485544526053376">connect to a website via HTTPS</a> when an HTTPS record is available from the domain name service (DNS).</p> <h3>InteractionID in EventTiming</h3> <p>The <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/PerformanceEventTiming">PerformanceEventTiming</a></code> interface now includes an attribute called <code>interactiveID</code>. This is a browser-generated ID that enables <a href="https://www.chromestatus.com/feature/5674224959094784">linking multiple <code>PerformanceEventTiming</code> entries</a> when they correspond to the same user interaction. Developers can currently use the Event Timing API to gather performance data about events they care about. Unfortunately, it is hard to link events that correspond to the same user interaction. For instance, when a user taps, many events are generated, such as <code>pointerdown</code>, <code>mousedown</code>, <code>pointerup</code>, <code>mouseup</code>, and <code>click</code>. </p> <h3>New Media Query: prefers-contrast</h3> <p>Chrome supports <a href="https://www.chromestatus.com/feature/5646323212615680">a new media query</a> called<code> 'prefers-contrast'</code>, which lets authors adapt web content to the user's contrast preference as set in the operating system (specifically, increased contrast mode on macOS and high contrast mode on Windows). Valid options are <code>'more'</code>, <code>'less'</code>, <code>'custom'</code>, or <code>'no-preference'</code>.</p> <h3>Unique id for Desktop PWAs</h3> <p>Web app <a href="https://developer.chrome.com/blog/pwa-manifest-id/">manifests now support an optional <code>id</code> field</a> that globally identifies a web app. When the <code>id</code> field is not present, a PWA falls back to <code>start_url</code>. This field is currently only supported on desktop.</p> <h3>URL Protocol Handler Registration for PWAs </h3> <p>Enable web applications to <a href="https://web.dev/url-protocol-handler/">register themselves as handlers of custom URL protocols/schemes</a> using their installation manifest. Operating system applications often register themselves as protocol handlers to increase discoverability and usage. Web sites can already register to handle schemes via <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/Navigator/registerProtocolHandler">registerProtocolHandler()</a></code>. The new feature takes this a step further by letting web apps be launched directly when a custom scheme link is invoked.</p> <h3>WebAssembly</h3> <h4>Content Security Policy</h4> <p>Chrome has <a href="https://www.chromestatus.com/feature/5499765773041664">enhanced Content Security Policy</a> to improve interoperability with WebAssembly. The <code>wasm-unsafe-eval</code> controls WebAssembly execution (with no effect on JavaScript execution). Additionally, the <code>script-src</code> policies now include WebAssembly.</p> <h4>Reference Types</h4> <p>WebAssembly modules can now <a href="https://www.chromestatus.com/feature/5166497248837632">hold references to JavaScript and DOM objects</a>. Specifically, they can be passed as arguments, stored in local and global variables, and stored in WebAssembly.Table objects.</p> <h2>Deprecations and Removals</h2> <p>This version of Chrome introduces the deprecations and removals listed below. Visit ChromeStatus.com for lists of <a href="https://www.chromestatus.com/features#browsers.chrome.status%3A%22Deprecated%22">current deprecations</a> and <a href="https://www.chromestatus.com/features#browsers.chrome.status:%22Removed%22">previous removals</a>.</p> <h3>The "basic-card" Method of PaymentRequest API</h3> <p>The <a href="https://developer.mozilla.org/en-US/docs/Web/API/Payment_Request_API">PaymentRequest API</a> has <a href="https://blog.chromium.org/2021/10/sunsetting-basic-card-payment-method-in.html">deprecated the basic card payment method</a>. Its usage is low and declining. It underperforms when compared to other payment methods in time-to-checkout and completion rate. Developers can switch to other payment methods as an alternative. Examples include Google Pay, Apple Pay, and Samsung Pay.<br /> <br /> Removal timeline:</p> <ul> <li>Chrome 96: the basic-card method is deprecated in the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Reporting_API">Reporting API</a>.</li> <li>Chrome 100: the basic-card method will be removed.</li> </ul> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <p>Unless otherwise noted, changes described below apply to the newest Chrome beta channel release for Android, Chrome OS, Linux, macOS, and Windows. Learn more about the features listed here through the provided links or from the list on <a href="https://www.chromestatus.com/features#milestone%3D76">ChromeStatus.com</a>. Chrome 96 is beta as of October 21, 2021.</p> <h2>Preparing for a Three Digit Version Number</h2> <p>Next year, Chrome will release version 100. This will add a digit to the version number reported in Chrome's user agent string. To help site owners test for the new string, Chrome 96 introduces a runtime flag that causes Chrome to return '100' in its user agent string. This new flag called <code>chrome://flags/#force-major-version-to-100</code> is available from Chrome 96 onward.</p> <h2>Origin Trials</h2> <p>This version of Chrome introduces the origin trials described below. Origin trials allow you to try new features and give feedback on usability, practicality, and effectiveness to the web standards community. To register for any of the origin trials currently supported in Chrome, including the ones described below, visit the <a href="https://developers.chrome.com/origintrials/#/trials/active">Chrome Origin Trials dashboard</a>. To learn more about origin trials in Chrome, visit the <a href="https://web.dev/origin-trials/">Origin Trials Guide for Web Developers</a>. Microsoft Edge runs its own origin trials separate from Chrome. To learn more, see the <a href="https://developer.microsoft.com/en-us/microsoft-edge/origin-trials/">Microsoft Edge Origin Trials Developer Console</a>. </p> <h3>New Origin Trials</h3> <h4>Conditional Focus</h4> <p>Applications that capture other windows or tabs currently have no way to control whether the calling item or the captured item gets focus. (Think of a presentation feature in a video conference app.) <a href="https://developer.chrome.com/origintrials/#/view_trial/4329085141809889281">Chrome 96 makes this possible</a> with a subclass of <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack">MediaStreamTrack</a></code> called <code>FocusableMediaStreamTrack</code>, which supports a new <code>focus()</code> method. Consider the following code:</p> <pre>stream = await navigator.mediaDevices.getDisplayMedia(); let [track] = stream.getVideoTracks(); </pre> <p>Where formerly, <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaStream/getVideoTracks">getVideoTracks()</a></code> would return an array of <code>MediaStreamTrack</code> objects, it now returns <code>FocusableMediaStreamTrack</code> objects. (Note that this is expected to change to <code>BrowserCaptureMediaStreamTrack</code> in Chrome 97. At the time of this writing, Canary already does this.)</p> <p>To determine which display media gets focus, the next line of this code would call <code>track.focus()</code> with either <code>"focus-captured-surface"</code> to focus the newly captured window or tab, or with <code>"no-focus-change"</code> to keep the focus with the calling window. On Chrome 96 or later, you can step through our <a href="https://eladalon1983.github.io/conditional-focus/demo/">demo code</a> to see this in action. </p> <h4>Priority Hints</h4> <p>Priority Hints <a href="https://web.dev/priority-hints/">introduces a developer-set <code>"importance"</code> attribute</a> to influence the computed priority of a resource. Supported importance values are <code>"auto"</code>, <code>"low"</code>, and <code>"high"</code>. Priority Hints indicate a resource's relative importance to the browser, allowing more control over the order resources are loaded. Many factors influence a resource's priority in browsers including type, visibility, and preload status of a resource.</p> <h2>Other Features in this Release</h2> <h3>Allow Simple Range Header Values Without Preflight</h3> <p>Requests with simple range headers<a href="https://www.chromestatus.com/feature/5652396366626816"> can now be sent</a> without <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#preflighted_requests">a preflight request</a>. CORS requests can use the Range header in limited ways (only one valid range) without triggering a preflight request.</p> <h3>Back-forward Cache on Desktop</h3> <p>The <a href="https://www.chromestatus.com/feature/5815270035685376">back-forward cache</a> stores pages to allow for instant navigations to previously-visited pages after cross-site navigations.</p> <h3>Cross-Origin-Embedder-Policy: credentialless</h3> <p><code>Cross-Origin-Embedder-Policy</code> has <a href="https://www.chromestatus.com/feature/4918234241302528">a new <code>credentialless</code> option</a> that causes cross-origin <code>no-cors</code> requests to omit credentials (cookies, client certificates, etc.). Similarly to <code>COEP:require-corp</code>, it can enable cross-origin isolation.</p> <p>Sites that want to continue using <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer">SharedArrayBuffer</a> must opt-in to cross-origin isolation. Doing so using <code>COEP: require-corp</code> is difficult to deploy at scale and requires all subresources to explicitly opt-in. This is fine for some sites, but creates dependency problems for sites that gather content from users (Google Earth, social media generally, forums, etc).</p> <h3>CSS</h3> <h4>:autofill Pseudo Class</h4> <p>The new <a href="https://www.chromestatus.com/feature/5592445322526720"><code>autofill</code> pseudo class</a> enables styling autofilled form elements. This is a standardization of the <code>:-webkit-autofill</code> pseudo class which is already supported in WebKit. Firefox supports the standard version.</p> <h4>Disable Propagation of Body Style to Viewport when Contained</h4> <p>Some properties like writing-mode, direction, and backgrounds are propagated from body to the viewport. To avoid infinite loops for CSS Container Queries, the<a href="https://www.chromestatus.com/feature/5663240823504896"> spec and implementation were changed</a> to not propagate those properties when containment is applied to HTML or BODY.</p> <h4>font-synthesis Property</h4> <p>The <a href="https://www.chromestatus.com/feature/5640605355999232"><code>font-synthesis</code> CSS property</a> controls whether user agents are allowed to synthesize oblique, bold, and small-caps font faces when a font family lacks faces.</p> <h3>EME MediaKeySession Closed Reason</h3> <p>The <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaKeySession/closed">MediaKeySession.closed</a></code> property <a href="https://www.chromestatus.com/feature/5632124143009792">now uses an enum to indicate the reason</a> the <code>MediaKeySession</code> object closed. The closed property returns a Promise that resolves when the session closes. Where previously, the Promise simply resolved, it <a href="https://www.google.com/url?q=https://googlechrome.github.io/samples/media/key-session-closed-reason.html&amp;sa=D&amp;source=docs&amp;ust=1634547430725000&amp;usg=AOvVaw3cXtJIna_rtEkWm9LLzyft">now resolves with a string</a> indicating the reason for closing. The returned string will be one of <code>"internal-error"</code>, <code>"closed-by-application"</code>, <code>"release-acknowledged"</code>, <code>"hardware-context-reset"</code>, or <code>"resource-evicted"</code>.</p> <h3>HTTP to HTTPS Redirect for HTTPS DNS Records</h3> <p>Chrome will always <a href="https://www.chromestatus.com/feature/5485544526053376">connect to a website via HTTPS</a> when an HTTPS record is available from the domain name service (DNS).</p> <h3>InteractionID in EventTiming</h3> <p>The <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/PerformanceEventTiming">PerformanceEventTiming</a></code> interface now includes an attribute called <code>interactiveID</code>. This is a browser-generated ID that enables <a href="https://www.chromestatus.com/feature/5674224959094784">linking multiple <code>PerformanceEventTiming</code> entries</a> when they correspond to the same user interaction. Developers can currently use the Event Timing API to gather performance data about events they care about. Unfortunately, it is hard to link events that correspond to the same user interaction. For instance, when a user taps, many events are generated, such as <code>pointerdown</code>, <code>mousedown</code>, <code>pointerup</code>, <code>mouseup</code>, and <code>click</code>. </p> <h3>New Media Query: prefers-contrast</h3> <p>Chrome supports <a href="https://www.chromestatus.com/feature/5646323212615680">a new media query</a> called<code> 'prefers-contrast'</code>, which lets authors adapt web content to the user's contrast preference as set in the operating system (specifically, increased contrast mode on macOS and high contrast mode on Windows). Valid options are <code>'more'</code>, <code>'less'</code>, <code>'custom'</code>, or <code>'no-preference'</code>.</p> <h3>Unique id for Desktop PWAs</h3> <p>Web app <a href="https://developer.chrome.com/blog/pwa-manifest-id/">manifests now support an optional <code>id</code> field</a> that globally identifies a web app. When the <code>id</code> field is not present, a PWA falls back to <code>start_url</code>. This field is currently only supported on desktop.</p> <h3>URL Protocol Handler Registration for PWAs </h3> <p>Enable web applications to <a href="https://web.dev/url-protocol-handler/">register themselves as handlers of custom URL protocols/schemes</a> using their installation manifest. Operating system applications often register themselves as protocol handlers to increase discoverability and usage. Web sites can already register to handle schemes via <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/Navigator/registerProtocolHandler">registerProtocolHandler()</a></code>. The new feature takes this a step further by letting web apps be launched directly when a custom scheme link is invoked.</p> <h3>WebAssembly</h3> <h4>Content Security Policy</h4> <p>Chrome has <a href="https://www.chromestatus.com/feature/5499765773041664">enhanced Content Security Policy</a> to improve interoperability with WebAssembly. The <code>wasm-unsafe-eval</code> controls WebAssembly execution (with no effect on JavaScript execution). Additionally, the <code>script-src</code> policies now include WebAssembly.</p> <h4>Reference Types</h4> <p>WebAssembly modules can now <a href="https://www.chromestatus.com/feature/5166497248837632">hold references to JavaScript and DOM objects</a>. Specifically, they can be passed as arguments, stored in local and global variables, and stored in WebAssembly.Table objects.</p> <h2>Deprecations and Removals</h2> <p>This version of Chrome introduces the deprecations and removals listed below. Visit ChromeStatus.com for lists of <a href="https://www.chromestatus.com/features#browsers.chrome.status%3A%22Deprecated%22">current deprecations</a> and <a href="https://www.chromestatus.com/features#browsers.chrome.status:%22Removed%22">previous removals</a>.</p> <h3>The "basic-card" Method of PaymentRequest API</h3> <p>The <a href="https://developer.mozilla.org/en-US/docs/Web/API/Payment_Request_API">PaymentRequest API</a> has <a href="https://blog.chromium.org/2021/10/sunsetting-basic-card-payment-method-in.html">deprecated the basic card payment method</a>. Its usage is low and declining. It underperforms when compared to other payment methods in time-to-checkout and completion rate. Developers can switch to other payment methods as an alternative. Examples include Google Pay, Apple Pay, and Samsung Pay.<br /> <br /> Removal timeline:</p> <ul> <li>Chrome 96: the basic-card method is deprecated in the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Reporting_API">Reporting API</a>.</li> <li>Chrome 100: the basic-card method will be removed.</li> </ul> <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 96 Beta: Conditional Focus, Priority Hints, and More&url=https://blog.chromium.org/2021/10/chrome-96-beta-conditional-focus.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/2021/10/chrome-96-beta-conditional-focus.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/2021/10/chrome-96-beta-conditional-focus.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> <span class='labels-caption'> Labels: </span> <span class='labels'> <a class='label' href='https://blog.chromium.org/search/label/beta' rel='tag'> beta </a> </span> </div> </div> </div> <div class='post' data-id='623981099780438302' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2021/10/sunsetting-basic-card-payment-method-in.html' itemprop='url' title='Sunsetting the "basic-card" payment method in the Payment Request API'> Sunsetting the "basic-card" payment method in the Payment Request API </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Thursday, October 21, 2021 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <span id="docs-internal-guid-2eee1d0a-7fff-a8f5-4003-7f6baac85b1a"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The</span><a href="https://www.w3.org/TR/payment-request/" style="text-decoration-line: none;"><span face="Roboto, sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;"> Payment Request API</span></a><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> is a </span><a href="https://www.w3.org/blog/news/archives/9269" style="text-decoration-line: none;"><span face="Roboto, sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">soon-to-be-recommended</span></a><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> web standard that aims to make building low-friction and secure payment flows easier for developers. The browser facilitates the flow between a merchant website and </span><span face="Roboto, sans-serif" style="font-size: 14.6667px; white-space: pre-wrap;">"</span><a href="https://web.dev/web-based-payment-apps-overview/#apis-you-can-use-inside-the-payment-handler-window" style="text-decoration-line: none;"><span face="Roboto, sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">payment handlers</span></a><span face="Roboto, sans-serif" style="font-size: 14.6667px; white-space: pre-wrap;">"</span><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. A payment handler can be built-in to the browser, a native app installed on user&#8217;s mobile device, or a </span><a href="https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps" style="text-decoration-line: none;"><span face="Roboto, sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">Progressive Web App</span></a><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. Today, developers can use the Payment Request API to access several payment methods, including &#8220;</span><a href="https://www.w3.org/TR/payment-method-basic-card/" style="text-decoration-line: none;"><span face="Roboto, sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">basic-card</span></a><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">&#8221; and Google Pay in Chrome on most platforms, Apple Pay in Safari, </span><a href="https://developer.chrome.com/docs/android/trusted-web-activity/receive-payments-play-billing/" style="text-decoration-line: none;"><span face="Roboto, sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">Digital Goods API</span></a><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> on Google Play, and </span><a href="https://github.com/w3c/secure-payment-confirmation/blob/main/explainer.md" style="text-decoration-line: none;"><span face="Roboto, sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">Secure Payment Confirmation</span></a><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> in Chrome.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Earlier last year, </span><a href="https://blog.chromium.org/2020/01/rethinking-payment-request-for-ios.html" style="text-decoration-line: none;"><span face="Roboto, sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">we announced</span></a><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> that we will deprecate the "basic-card" payment handler on iOS Chrome, followed by other platforms in the future. The "basic-card" is a payment method that is typically built into the browser to help users easily enter credit card numbers without remembering and typing them. This was designed to make a good transition from a form based credit card payment to an app based tokenized card payment. In order to better pursue the goal of app based payment (and </span><a href="https://lists.w3.org/Archives/Public/public-payments-wg/2021Aug/0020.html" style="text-decoration-line: none;"><span face="Roboto, sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">a few other reasons</span></a><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">), the Web Payments WG </span><a href="https://lists.w3.org/Archives/Public/public-payments-wg/2021Aug/0038.html" style="text-decoration-line: none;"><span face="Roboto, sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">decided to remove it from the specification</span></a><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Starting from version 96, Chrome will show a warning message in DevTools Console (together with creating a report to Reporting API) when the "basic-card" payment method is used. In version 100, the "basic-card" payment method will be no longer available and </span><a href="https://web.dev/how-payment-request-api-works/#check-whether-the-payment-method-is-available" style="text-decoration-line: none;"><span style="color: #1155cc; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: courier;">canMakePayment()</span></span></a><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> will return </span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: courier;">false</span></span><span face="Roboto, sans-serif" style="font-size: 11pt; white-space: pre-wrap;"> unless other capable payment methods are specified. This applies to all platforms including Android, macOS, Windows, Linux, and Chrome OS.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">If you are using the Payment Request API with the "basic-card" payment handler, we suggest removing it as soon as possible and using an alternative payment method such as Google Pay</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> or Samsung Pay</span><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span></p><div><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div><div><span style="color: #202124; font-family: Roboto, sans-serif;"><span style="background-color: white; font-size: 14px; white-space: pre-wrap;">Posted by Eiji Kitamura, Developer Advocate on the Chrome team</span></span></div></span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <span id="docs-internal-guid-2eee1d0a-7fff-a8f5-4003-7f6baac85b1a"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The</span><a href="https://www.w3.org/TR/payment-request/" style="text-decoration-line: none;"><span face="Roboto, sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;"> Payment Request API</span></a><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> is a </span><a href="https://www.w3.org/blog/news/archives/9269" style="text-decoration-line: none;"><span face="Roboto, sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">soon-to-be-recommended</span></a><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> web standard that aims to make building low-friction and secure payment flows easier for developers. The browser facilitates the flow between a merchant website and </span><span face="Roboto, sans-serif" style="font-size: 14.6667px; white-space: pre-wrap;">"</span><a href="https://web.dev/web-based-payment-apps-overview/#apis-you-can-use-inside-the-payment-handler-window" style="text-decoration-line: none;"><span face="Roboto, sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">payment handlers</span></a><span face="Roboto, sans-serif" style="font-size: 14.6667px; white-space: pre-wrap;">"</span><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. A payment handler can be built-in to the browser, a native app installed on user&#8217;s mobile device, or a </span><a href="https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps" style="text-decoration-line: none;"><span face="Roboto, sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">Progressive Web App</span></a><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. Today, developers can use the Payment Request API to access several payment methods, including &#8220;</span><a href="https://www.w3.org/TR/payment-method-basic-card/" style="text-decoration-line: none;"><span face="Roboto, sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">basic-card</span></a><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">&#8221; and Google Pay in Chrome on most platforms, Apple Pay in Safari, </span><a href="https://developer.chrome.com/docs/android/trusted-web-activity/receive-payments-play-billing/" style="text-decoration-line: none;"><span face="Roboto, sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">Digital Goods API</span></a><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> on Google Play, and </span><a href="https://github.com/w3c/secure-payment-confirmation/blob/main/explainer.md" style="text-decoration-line: none;"><span face="Roboto, sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">Secure Payment Confirmation</span></a><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> in Chrome.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Earlier last year, </span><a href="https://blog.chromium.org/2020/01/rethinking-payment-request-for-ios.html" style="text-decoration-line: none;"><span face="Roboto, sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">we announced</span></a><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> that we will deprecate the "basic-card" payment handler on iOS Chrome, followed by other platforms in the future. The "basic-card" is a payment method that is typically built into the browser to help users easily enter credit card numbers without remembering and typing them. This was designed to make a good transition from a form based credit card payment to an app based tokenized card payment. In order to better pursue the goal of app based payment (and </span><a href="https://lists.w3.org/Archives/Public/public-payments-wg/2021Aug/0020.html" style="text-decoration-line: none;"><span face="Roboto, sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">a few other reasons</span></a><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">), the Web Payments WG </span><a href="https://lists.w3.org/Archives/Public/public-payments-wg/2021Aug/0038.html" style="text-decoration-line: none;"><span face="Roboto, sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">decided to remove it from the specification</span></a><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Starting from version 96, Chrome will show a warning message in DevTools Console (together with creating a report to Reporting API) when the "basic-card" payment method is used. In version 100, the "basic-card" payment method will be no longer available and </span><a href="https://web.dev/how-payment-request-api-works/#check-whether-the-payment-method-is-available" style="text-decoration-line: none;"><span style="color: #1155cc; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: courier;">canMakePayment()</span></span></a><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> will return </span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: courier;">false</span></span><span face="Roboto, sans-serif" style="font-size: 11pt; white-space: pre-wrap;"> unless other capable payment methods are specified. This applies to all platforms including Android, macOS, Windows, Linux, and Chrome OS.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">If you are using the Payment Request API with the "basic-card" payment handler, we suggest removing it as soon as possible and using an alternative payment method such as Google Pay</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> or Samsung Pay</span><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span></p><div><span face="Roboto, sans-serif" style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div><div><span style="color: #202124; font-family: Roboto, sans-serif;"><span style="background-color: white; font-size: 14px; white-space: pre-wrap;">Posted by Eiji Kitamura, Developer Advocate on the Chrome team</span></span></div></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:Sunsetting the "basic-card" payment method in the Payment Request API&url=https://blog.chromium.org/2021/10/sunsetting-basic-card-payment-method-in.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/2021/10/sunsetting-basic-card-payment-method-in.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/2021/10/sunsetting-basic-card-payment-method-in.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> <span class='labels-caption'> Labels: </span> <span class='labels'> <a class='label' href='https://blog.chromium.org/search/label/beta' rel='tag'> beta </a> </span> </div> </div> </div> <div class='post' data-id='2400803839907461254' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://blog.chromium.org/2021/10/extending-chrome-app-support-on-chrome.html' itemprop='url' title='Extending Chrome App Support on Chrome OS'> Extending Chrome App Support on Chrome OS </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Thursday, October 14, 2021 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <span class="post-author" style="font-family: inherit;">Posted by Paul Rossman, Technical Program Manager, Chrome</span><div><br /></div><div><span class="post-author" style="font-family: inherit;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Today we're announcing an important update to the </span><a href="https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration-skip-ink: none; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">previously communicated</span></a><span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> Chrome app support timeline. Based on feedback from our Enterprise and Education customers and partners, we have made the decision to extend </span><a href="https://developer.chrome.com/docs/apps/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration-skip-ink: none; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Chrome app</span></a><span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> support for those users on Chrome OS until at least January 2025.&nbsp;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><b id="docs-internal-guid-32622266-7fff-273f-d5c8-a14a937da396" style="font-weight: normal;"><br /></b></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We continue to invest and have made significant progress in rich new capabilities on the Web platform with </span><a href="https://web.dev/what-are-pwas/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration-skip-ink: none; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Progressive Web Apps (PWA)</span></a><span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, and we recommend that Chrome app developers migrate to PWAs as soon as possible. PWAs are built and enhanced with </span><a href="https://fugu-tracker.web.app/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration-skip-ink: none; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">modern APIs</span></a><span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to deliver enhanced capabilities, reliability, and installability while reaching anyone, anywhere, on any device with a single codebase. There is a growing ecosystem of powerful desktop web apps &amp; PWAs, from advanced graphics products like Adobe Spark to engaging media apps like YouTube TV to productivity and collaboration apps like Zoom.</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><b style="font-weight: normal;"><br /></b></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">For additional support with Chrome app migration, please visit our </span><a href="https://chromeos.dev/en/web" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration-skip-ink: none; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Web apps on Chrome OS page</span></a><span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. This page will be kept up to date as we progress together through this process.</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We thank our community of developers who have provided feedback to help us shape this modified and simplified approach. We are inspired by a future beyond Chrome apps, where the ecosystem continues forward progress leveraging open Web standards across all modern browsers.</span></p></span></div> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <span class="post-author" style="font-family: inherit;">Posted by Paul Rossman, Technical Program Manager, Chrome</span><div><br /></div><div><span class="post-author" style="font-family: inherit;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Today we're announcing an important update to the </span><a href="https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration-skip-ink: none; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">previously communicated</span></a><span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> Chrome app support timeline. Based on feedback from our Enterprise and Education customers and partners, we have made the decision to extend </span><a href="https://developer.chrome.com/docs/apps/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration-skip-ink: none; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Chrome app</span></a><span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> support for those users on Chrome OS until at least January 2025.&nbsp;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><b id="docs-internal-guid-32622266-7fff-273f-d5c8-a14a937da396" style="font-weight: normal;"><br /></b></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We continue to invest and have made significant progress in rich new capabilities on the Web platform with </span><a href="https://web.dev/what-are-pwas/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration-skip-ink: none; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Progressive Web Apps (PWA)</span></a><span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, and we recommend that Chrome app developers migrate to PWAs as soon as possible. PWAs are built and enhanced with </span><a href="https://fugu-tracker.web.app/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration-skip-ink: none; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">modern APIs</span></a><span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to deliver enhanced capabilities, reliability, and installability while reaching anyone, anywhere, on any device with a single codebase. There is a growing ecosystem of powerful desktop web apps &amp; PWAs, from advanced graphics products like Adobe Spark to engaging media apps like YouTube TV to productivity and collaboration apps like Zoom.</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><b style="font-weight: normal;"><br /></b></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">For additional support with Chrome app migration, please visit our </span><a href="https://chromeos.dev/en/web" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration-skip-ink: none; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Web apps on Chrome OS page</span></a><span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. This page will be kept up to date as we progress together through this process.</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We thank our community of developers who have provided feedback to help us shape this modified and simplified approach. We are inspired by a future beyond Chrome apps, where the ecosystem continues forward progress leveraging open Web standards across all modern browsers.</span></p></span></div> <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:Extending Chrome App Support on Chrome OS&url=https://blog.chromium.org/2021/10/extending-chrome-app-support-on-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/2021/10/extending-chrome-app-support-on-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/2021/10/extending-chrome-app-support-on-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='blog-pager' id='blog-pager'> <a class='home-link' href='https://blog.chromium.org/'> <i class='material-icons'> &#59530; </i> </a> <span id='blog-pager-newer-link'> <a class='blog-pager-newer-link' href='https://blog.chromium.org/search?updated-max=2022-04-28T11:51:00-07:00&max-results=7&reverse-paginate=true' id='Blog1_blog-pager-newer-link' title='Newer Posts'> <i class='material-icons'> &#58820; </i> </a> </span> <span id='blog-pager-older-link'> <a class='blog-pager-older-link' href='https://blog.chromium.org/search?updated-max=2021-10-14T08:00:00-07:00&max-results=7' id='Blog1_blog-pager-older-link' title='Older Posts'> <i class='material-icons'> &#58824; </i> </a> </span> </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'> &#58821; </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'> &#58055; </i> <h2> Archive </h2> <i class='material-icons arrow'> &#58821; </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'> &#58821; </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'> &#58821; </i> &#160; </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'> &#58821; </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'> &#58821; </i> &#160; </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'> &#58821; </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'> &#58821; </i> &#160; </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 expanded'> <div class='intervalToggle'> <span class='new-toggle' href='javascript:void(0)'> <i class='material-icons arrow'> &#58821; </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy toggle-open'> <i class='material-icons'> &#58823; </i> &#160; </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 expanded'> <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'> &#58821; </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'> &#58821; </i> &#160; </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'> &#58821; </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'> &#58821; </i> &#160; </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'> &#58821; </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'> &#58821; </i> &#160; </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'> &#58821; </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'> &#58821; </i> &#160; </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'> &#58821; </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'> &#58821; </i> &#160; </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'> &#58821; </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'> &#58821; </i> &#160; </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'> &#58821; </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'> &#58821; </i> &#160; </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'> &#58821; </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'> &#58821; </i> &#160; </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'> &#58821; </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'> &#58821; </i> &#160; </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'> &#58821; </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'> &#58821; </i> &#160; </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'> &#58821; </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'> &#58821; </i> &#160; </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'> &#58821; </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'> &#58821; </i> &#160; </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 collapsed'> <div class='intervalToggle'> <span class='new-toggle' href='javascript:void(0)'> <i class='material-icons arrow'> &#58821; </i> </span> <a class='toggle' href='javascript:void(0)' style='display: none'> <span class='zippy'> <i class='material-icons'> &#58821; </i> &#160; </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 collapsed'> <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/&amp;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'] = 'AOuZoY6AyjqruXvnijIFIIG6tL6a1-ZrpA:1732419022780';_WidgetManager._Init('//www.blogger.com/rearrange?blogID\x3d2471378914199150966','//blog.chromium.org/2021/','2471378914199150966'); _WidgetManager._SetDataContext([{'name': 'blog', 'data': {'blogId': '2471378914199150966', 'title': 'Chromium Blog', 'url': 'https://blog.chromium.org/2021/', 'canonicalUrl': 'https://blog.chromium.org/2021/', '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': '2021', 'pageTitle': 'Chromium Blog: 2021'}}, {'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/2021/', 'type': 'feed', 'isSingleItem': false, 'isMultipleItems': true, 'isError': false, 'isPage': false, 'isPost': false, 'isHomepage': false, 'isArchive': true, 'isLabelSearch': false, 'archive': {'year': 2021, 'rangeMessage': 'Showing posts from 2021'}}}]); _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>

Pages: 1 2 3 4 5 6 7 8 9 10