<!doctype html><html lang="en">
 <head>
  <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  <meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport">
  <title>P1108R4: web_view</title>
<style data-fill-with="stylesheet">/******************************************************************************
 *                   Style sheet for the W3C specifications                   *
 *
 * Special classes handled by this style sheet include:
 *
 * Indices
 *   - .toc for the Table of Contents (<ol class="toc">)
 *     + <span class="secno"> for the section numbers
 *   - #toc for the Table of Contents (<nav id="toc">)
 *   - ul.index for Indices (<a href="#ref">term</a><span>, in §N.M</span>)
 *   - table.index for Index Tables (e.g. for properties or elements)
 *
 * Structural Markup
 *   - table.data for general data tables
 *     -> use 'scope' attribute, <colgroup>, <thead>, and <tbody> for best results !
 *     -> use <table class='complex data'> for extra-complex tables
 *     -> use <td class='long'> for paragraph-length cell content
 *     -> use <td class='pre'> when manual line breaks/indentation would help readability
 *   - dl.switch for switch statements
 *   - ol.algorithm for algorithms (helps to visualize nesting)
 *   - .figure and .caption (HTML4) and figure and figcaption (HTML5)
 *     -> .sidefigure for right-floated figures
 *   - ins/del
 *
 * Code
 *   - pre and code
 *
 * Special Sections
 *   - .note       for informative notes             (div, p, span, aside, details)
 *   - .example    for informative examples          (div, p, pre, span)
 *   - .issue      for issues                        (div, p, span)
 *   - .assertion  for assertions                    (div, p, span)
 *   - .advisement for loud normative statements     (div, p, strong)
 *   - .annoying-warning for spec obsoletion notices (div, aside, details)
 *
 * Definition Boxes
 *   - pre.def   for WebIDL definitions
 *   - table.def for tables that define other entities (e.g. CSS properties)
 *   - dl.def    for definition lists that define other entitles (e.g. HTML elements)
 *
 * Numbering
 *   - .secno for section numbers in .toc and headings (<span class='secno'>3.2</span>)
 *   - .marker for source-inserted example/figure/issue numbers (<span class='marker'>Issue 4</span>)
 *   - ::before styled for CSS-generated issue/example/figure numbers:
 *     -> Documents wishing to use this only need to add
 *        figcaption::before,
 *        .caption::before { content: "Figure "  counter(figure) " ";  }
 *        .example::before { content: "Example " counter(example) " "; }
 *        .issue::before   { content: "Issue "   counter(issue) " ";   }
 *
 * Header Stuff (ignore, just don't conflict with these classes)
 *   - .head for the header
 *   - .copyright for the copyright
 *
 * Miscellaneous
 *   - .overlarge for things that should be as wide as possible, even if
 *     that overflows the body text area. This can be used on an item or
 *     on its container, depending on the effect desired.
 *     Note that this styling basically doesn't help at all when printing,
 *     since A4 paper isn't much wider than the max-width here.
 *     It's better to design things to fit into a narrower measure if possible.
 *   - js-added ToC jump links (see fixup.js)
 *
 ******************************************************************************/

/******************************************************************************/
/*                                   Body                                     */
/******************************************************************************/

	body {
		counter-reset: example figure issue;

		/* Layout */
		max-width: 50em;               /* limit line length to 50em for readability   */
		margin: 0 auto;                /* center text within page                     */
		padding: 1.6em 1.5em 2em 50px; /* assume 16px font size for downlevel clients */
		padding: 1.6em 1.5em 2em calc(26px + 1.5em); /* leave space for status flag     */

		/* Typography */
		line-height: 1.5;
		font-family: sans-serif;
		widows: 2;
		orphans: 2;
		word-wrap: break-word;
		overflow-wrap: break-word;
		hyphens: auto;

		/* Colors */
		color: black;
		background: white top left fixed no-repeat;
		background-size: 25px auto;
	}


/******************************************************************************/
/*                         Front Matter & Navigation                          */
/******************************************************************************/

/** Header ********************************************************************/

	div.head { margin-bottom: 1em }
	div.head hr { border-style: solid; }

	div.head h1 {
		font-weight: bold;
		margin: 0 0 .1em;
		font-size: 220%;
	}

	div.head h2 { margin-bottom: 1.5em;}

/** W3C Logo ******************************************************************/

	.head .logo {
		float: right;
		margin: 0.4rem 0 0.2rem .4rem;
	}

	.head img[src*="logos/W3C"] {
		display: block;
		border: solid #1a5e9a;
		border-width: .65rem .7rem .6rem;
		border-radius: .4rem;
		background: #1a5e9a;
		color: white;
		font-weight: bold;
	}

	.head a:hover > img[src*="logos/W3C"],
	.head a:focus > img[src*="logos/W3C"] {
		opacity: .8;
	}

	.head a:active > img[src*="logos/W3C"] {
		background: #c00;
		border-color: #c00;
	}

	/* see also additional rules in Link Styling section */

/** Copyright *****************************************************************/

	p.copyright,
	p.copyright small { font-size: small }

/** Back to Top / ToC Toggle **************************************************/

	@media print {
		#toc-nav {
			display: none;
		}
	}
	@media not print {
		#toc-nav {
			position: fixed;
			z-index: 2;
			bottom: 0; left: 0;
			margin: 0;
			min-width: 1.33em;
			border-top-right-radius: 2rem;
			box-shadow: 0 0 2px;
			font-size: 1.5em;
			color: black;
		}
		#toc-nav > a {
			display: block;
			white-space: nowrap;

			height: 1.33em;
			padding: .1em 0.3em;
			margin: 0;

			background: white;
			box-shadow: 0 0 2px;
			border: none;
			border-top-right-radius: 1.33em;
			background: white;
		}
		#toc-nav > #toc-jump {
			padding-bottom: 2em;
			margin-bottom: -1.9em;
		}

		#toc-nav > a:hover,
		#toc-nav > a:focus {
			background: #f8f8f8;
		}
		#toc-nav > a:not(:hover):not(:focus) {
			color: #707070;
		}

		/* statusbar gets in the way on keyboard focus; remove once browsers fix */
		#toc-nav > a[href="#toc"]:not(:hover):focus:last-child {
			padding-bottom: 1.5rem;
		}

		#toc-nav:not(:hover) > a:not(:focus) > span + span {
			/* Ideally this uses :focus-within on #toc-nav */
			display: none;
		}
		#toc-nav > a > span + span {
			padding-right: 0.2em;
		}

		#toc-toggle-inline {
			vertical-align: 0.05em;
			font-size: 80%;
			color: gray;
			color: hsla(203,20%,40%,.7);
			border-style: none;
			background: transparent;
			position: relative;
		}
		#toc-toggle-inline:hover:not(:active),
		#toc-toggle-inline:focus:not(:active) {
			text-shadow: 1px 1px silver;
			top: -1px;
			left: -1px;
		}

		#toc-nav :active {
			color: #C00;
		}
	}

/** ToC Sidebar ***************************************************************/

	/* Floating sidebar */
	@media screen {
		body.toc-sidebar #toc {
			position: fixed;
			top: 0; bottom: 0;
			left: 0;
			width: 23.5em;
			max-width: 80%;
			max-width: calc(100% - 2em - 26px);
			overflow: auto;
			padding: 0 1em;
			padding-left: 42px;
			padding-left: calc(1em + 26px);
			background: inherit;
			background-color: #f7f8f9;
			z-index: 1;
			box-shadow: -.1em 0 .25em rgba(0,0,0,.1) inset;
		}
		body.toc-sidebar #toc h2 {
			margin-top: .8rem;
			font-variant: small-caps;
			font-variant: all-small-caps;
			text-transform: lowercase;
			font-weight: bold;
			color: gray;
			color: hsla(203,20%,40%,.7);
		}
		body.toc-sidebar #toc-jump:not(:focus) {
			width: 0;
			height: 0;
			padding: 0;
			position: absolute;
			overflow: hidden;
		}
	}
	/* Hide main scroller when only the ToC is visible anyway */
	@media screen and (max-width: 28em) {
		body.toc-sidebar {
			overflow: hidden;
		}
	}

	/* Sidebar with its own space */
	@media screen and (min-width: 78em) {
		body:not(.toc-inline) #toc {
			position: fixed;
			top: 0; bottom: 0;
			left: 0;
			width: 23.5em;
			overflow: auto;
			padding: 0 1em;
			padding-left: 42px;
			padding-left: calc(1em + 26px);
			background: inherit;
			background-color: #f7f8f9;
			z-index: 1;
			box-shadow: -.1em 0 .25em rgba(0,0,0,.1) inset;
		}
		body:not(.toc-inline) #toc h2 {
			margin-top: .8rem;
			font-variant: small-caps;
			font-variant: all-small-caps;
			text-transform: lowercase;
			font-weight: bold;
			color: gray;
			color: hsla(203,20%,40%,.7);
		}

		body:not(.toc-inline) {
			padding-left: 29em;
		}
		/* See also Overflow section at the bottom */

		body:not(.toc-inline) #toc-jump:not(:focus) {
			width: 0;
			height: 0;
			padding: 0;
			position: absolute;
			overflow: hidden;
		}
	}
	@media screen and (min-width: 90em) {
		body:not(.toc-inline) {
			margin: 0 4em;
		}
	}

/******************************************************************************/
/*                                Sectioning                                  */
/******************************************************************************/

/** Headings ******************************************************************/

	h1, h2, h3, h4, h5, h6, dt {
		page-break-after: avoid;
		page-break-inside: avoid;
		font: 100% sans-serif;   /* Reset all font styling to clear out UA styles */
		font-family: inherit;    /* Inherit the font family. */
		line-height: 1.2;        /* Keep wrapped headings compact */
		hyphens: manual;         /* Hyphenated headings look weird */
	}

	h2, h3, h4, h5, h6 {
		margin-top: 3rem;
	}

	h1, h2, h3 {
		color: #005A9C;
		background: transparent;
	}

	h1 { font-size: 170%; }
	h2 { font-size: 140%; }
	h3 { font-size: 120%; }
	h4 { font-weight: bold; }
	h5 { font-style: italic; }
	h6 { font-variant: small-caps; }
	dt { font-weight: bold; }

/** Subheadings ***************************************************************/

	h1 + h2,
	#subtitle {
		/* #subtitle is a subtitle in an H2 under the H1 */
		margin-top: 0;
	}
	h2 + h3,
	h3 + h4,
	h4 + h5,
	h5 + h6 {
		margin-top: 1.2em; /* = 1 x line-height */
	}

/** Section divider ***********************************************************/

	:not(.head) > hr {
		font-size: 1.5em;
		text-align: center;
		margin: 1em auto;
		height: auto;
		border: transparent solid 0;
		background: transparent;
	}
	:not(.head) > hr::before {
		content: "\2727\2003\2003\2727\2003\2003\2727";
	}

/******************************************************************************/
/*                            Paragraphs and Lists                            */
/******************************************************************************/

	p {
		margin: 1em 0;
	}

	dd > p:first-child,
	li > p:first-child {
		margin-top: 0;
	}

	ul, ol {
		margin-left: 0;
		padding-left: 2em;
	}

	li {
		margin: 0.25em 0 0.5em;
		padding: 0;
	}

	dl dd {
		margin: 0 0 .5em 2em;
	}

	.head dd + dd { /* compact for header */
		margin-top: -.5em;
	}

	/* Style for algorithms */
	ol.algorithm ol:not(.algorithm),
	.algorithm > ol ol:not(.algorithm) {
	 border-left: 0.5em solid #DEF;
	}

	/* Put nice boxes around each algorithm. */
	[data-algorithm]:not(.heading) {
	  padding: .5em;
	  border: thin solid #ddd; border-radius: .5em;
	  margin: .5em calc(-0.5em - 1px);
	}
	[data-algorithm]:not(.heading) > :first-child {
	  margin-top: 0;
	}
	[data-algorithm]:not(.heading) > :last-child {
	  margin-bottom: 0;
	}

	/* Style for switch/case <dl>s */
	dl.switch > dd > ol.only,
	dl.switch > dd > .only > ol {
	 margin-left: 0;
	}
	dl.switch > dd > ol.algorithm,
	dl.switch > dd > .algorithm > ol {
	 margin-left: -2em;
	}
	dl.switch {
	 padding-left: 2em;
	}
	dl.switch > dt {
	 text-indent: -1.5em;
	 margin-top: 1em;
	}
	dl.switch > dt + dt {
	 margin-top: 0;
	}
	dl.switch > dt::before {
	 content: '\21AA';
	 padding: 0 0.5em 0 0;
	 display: inline-block;
	 width: 1em;
	 text-align: right;
	 line-height: 0.5em;
	}

/** Terminology Markup ********************************************************/


/******************************************************************************/
/*                                 Inline Markup                              */
/******************************************************************************/

/** Terminology Markup ********************************************************/
	dfn   { /* Defining instance */
		font-weight: bolder;
	}
	a > i { /* Instance of term */
		font-style: normal;
	}
	dt dfn code, code.idl {
		font-size: medium;
	}
	dfn var {
		font-style: normal;
	}

/** Change Marking ************************************************************/

	del { color: red;  text-decoration: line-through; }
	ins { color: #080; text-decoration: underline;    }

/** Miscellaneous improvements to inline formatting ***************************/

	sup {
		vertical-align: super;
		font-size: 80%
	}

/******************************************************************************/
/*                                    Code                                    */
/******************************************************************************/

/** General monospace/pre rules ***********************************************/

	pre, code, samp {
		font-family: Menlo, Consolas, "DejaVu Sans Mono", Monaco, monospace;
		font-size: .9em;
		page-break-inside: avoid;
		hyphens: none;
		text-transform: none;
	}
	pre code,
	code code {
		font-size: 100%;
	}

	pre {
		margin-top: 1em;
		margin-bottom: 1em;
		overflow: auto;
	}

/** Inline Code fragments *****************************************************/

  /* Do something nice. */

/******************************************************************************/
/*                                    Links                                   */
/******************************************************************************/

/** General Hyperlinks ********************************************************/

	/* We hyperlink a lot, so make it less intrusive */
	a[href] {
		color: #034575;
		text-decoration: none;
		border-bottom: 1px solid #707070;
		/* Need a bit of extending for it to look okay */
		padding: 0 1px 0;
		margin: 0 -1px 0;
	}
	a:visited {
		border-bottom-color: #BBB;
	}

	/* Use distinguishing colors when user is interacting with the link */
	a[href]:focus,
	a[href]:hover {
		background: #f8f8f8;
		background: rgba(75%, 75%, 75%, .25);
		border-bottom-width: 3px;
		margin-bottom: -2px;
	}
	a[href]:active {
		color: #C00;
		border-color: #C00;
	}

	/* Backout above styling for W3C logo */
	.head .logo,
	.head .logo a {
		border: none;
		text-decoration: none;
		background: transparent;
	}

/******************************************************************************/
/*                                    Images                                  */
/******************************************************************************/

	img {
		border-style: none;
	}

	/* For autogen numbers, add
	   .caption::before, figcaption::before { content: "Figure " counter(figure) ". "; }
	*/

	figure, .figure, .sidefigure {
		page-break-inside: avoid;
		text-align: center;
		margin: 2.5em 0;
	}
	.figure img,    .sidefigure img,    figure img,
	.figure object, .sidefigure object, figure object {
		max-width: 100%;
		margin: auto;
	}
	.figure pre, .sidefigure pre, figure pre {
		text-align: left;
		display: table;
		margin: 1em auto;
	}
	.figure table, figure table {
		margin: auto;
	}
	@media screen and (min-width: 20em) {
		.sidefigure {
			float: right;
			width: 50%;
			margin: 0 0 0.5em 0.5em
		}
	}
	.caption, figcaption, caption {
		font-style: italic;
		font-size: 90%;
	}
	.caption::before, figcaption::before, figcaption > .marker {
		font-weight: bold;
	}
	.caption, figcaption {
		counter-increment: figure;
	}

	/* DL list is indented 2em, but figure inside it is not */
	dd > .figure, dd > figure { margin-left: -2em }

/******************************************************************************/
/*                             Colored Boxes                                  */
/******************************************************************************/

	.issue, .note, .example, .assertion, .advisement, blockquote {
		padding: .5em;
		border: .5em;
		border-left-style: solid;
		page-break-inside: avoid;
	}
	span.issue, span.note {
		padding: .1em .5em .15em;
		border-right-style: solid;
	}

	.issue,
	.note,
	.example,
	.advisement,
	.assertion,
	blockquote {
		margin: 1em auto;
	}
	.note  > p:first-child,
	.issue > p:first-child,
	blockquote > :first-child {
		margin-top: 0;
	}
	blockquote > :last-child {
		margin-bottom: 0;
	}

/** Blockquotes ***************************************************************/

	blockquote {
		border-color: silver;
	}

/** Open issue ****************************************************************/

	.issue {
		border-color: #E05252;
		background: #FBE9E9;
		counter-increment: issue;
		overflow: auto;
	}
	.issue::before, .issue > .marker {
		text-transform: uppercase;
		color: #AE1E1E;
		padding-right: 1em;
		text-transform: uppercase;
	}
	/* Add .issue::before { content: "Issue " counter(issue) " "; } for autogen numbers,
	   or use class="marker" to mark up the issue number in source. */

/** Example *******************************************************************/

	.example {
		border-color: #E0CB52;
		background: #FCFAEE;
		counter-increment: example;
		overflow: auto;
		clear: both;
	}
	.example::before, .example > .marker {
		text-transform: uppercase;
		color: #827017;
		min-width: 7.5em;
		display: block;
	}
	/* Add .example::before { content: "Example " counter(example) " "; } for autogen numbers,
	   or use class="marker" to mark up the example number in source. */

/** Non-normative Note ********************************************************/

	.note {
		border-color: #52E052;
		background: #E9FBE9;
		overflow: auto;
	}

	.note::before, .note > .marker,
	details.note > summary::before,
	details.note > summary > .marker {
		text-transform: uppercase;
		display: block;
		color: hsl(120, 70%, 30%);
	}
	/* Add .note::before { content: "Note"; } for autogen label,
	   or use class="marker" to mark up the label in source. */

	details.note > summary {
		display: block;
		color: hsl(120, 70%, 30%);
	}
	details.note[open] > summary {
		border-bottom: 1px silver solid;
	}

/** Assertion Box *************************************************************/
	/*  for assertions in algorithms */

	.assertion {
		border-color: #AAA;
		background: #EEE;
	}

/** Advisement Box ************************************************************/
	/*  for attention-grabbing normative statements */

	.advisement {
		border-color: orange;
		border-style: none solid;
		background: #FFEECC;
	}
	strong.advisement {
		display: block;
		text-align: center;
	}
	.advisement > .marker {
		color: #B35F00;
	}

/** Spec Obsoletion Notice ****************************************************/
	/* obnoxious obsoletion notice for older/abandoned specs. */

	details {
		display: block;
	}
	summary {
		font-weight: bolder;
	}

	.annoying-warning:not(details),
	details.annoying-warning:not([open]) > summary,
	details.annoying-warning[open] {
		background: #fdd;
		color: red;
		font-weight: bold;
		padding: .75em 1em;
		border: thick red;
		border-style: solid;
		border-radius: 1em;
	}
	.annoying-warning :last-child {
		margin-bottom: 0;
	}

@media not print {
	details.annoying-warning[open] {
		position: fixed;
		left: 1em;
		right: 1em;
		bottom: 1em;
		z-index: 1000;
	}
}

	details.annoying-warning:not([open]) > summary {
		text-align: center;
	}

/** Entity Definition Boxes ***************************************************/

	.def {
		padding: .5em 1em;
		background: #DEF;
		margin: 1.2em 0;
		border-left: 0.5em solid #8CCBF2;
	}

/******************************************************************************/
/*                                    Tables                                  */
/******************************************************************************/

	th, td {
		text-align: left;
		text-align: start;
	}

/** Property/Descriptor Definition Tables *************************************/

	table.def {
		/* inherits .def box styling, see above */
		width: 100%;
		border-spacing: 0;
	}

	table.def td,
	table.def th {
		padding: 0.5em;
		vertical-align: baseline;
		border-bottom: 1px solid #bbd7e9;
	}

	table.def > tbody > tr:last-child th,
	table.def > tbody > tr:last-child td {
		border-bottom: 0;
	}

	table.def th {
		font-style: italic;
		font-weight: normal;
		padding-left: 1em;
		width: 3em;
	}

	/* For when values are extra-complex and need formatting for readability */
	table td.pre {
		white-space: pre-wrap;
	}

	/* A footnote at the bottom of a def table */
	table.def           td.footnote {
		padding-top: 0.6em;
	}
	table.def           td.footnote::before {
		content: " ";
		display: block;
		height: 0.6em;
		width: 4em;
		border-top: thin solid;
	}

/** Data tables (and properly marked-up index tables) *************************/
	/*
		 <table class="data"> highlights structural relationships in a table
		 when correct markup is used (e.g. thead/tbody, th vs. td, scope attribute)

		 Use class="complex data" for particularly complicated tables --
		 (This will draw more lines: busier, but clearer.)

		 Use class="long" on table cells with paragraph-like contents
		 (This will adjust text alignment accordingly.)
		 Alternately use class="longlastcol" on tables, to have the last column assume "long".
	*/

	table {
		word-wrap: normal;
		overflow-wrap: normal;
		hyphens: manual;
	}

	table.data,
	table.index {
		margin: 1em auto;
		border-collapse: collapse;
		border: hidden;
		width: 100%;
	}
	table.data caption,
	table.index caption {
		max-width: 50em;
		margin: 0 auto 1em;
	}

	table.data td,  table.data th,
	table.index td, table.index th {
		padding: 0.5em 1em;
		border-width: 1px;
		border-color: silver;
		border-top-style: solid;
	}

	table.data thead td:empty {
		padding: 0;
		border: 0;
	}

	table.data  thead,
	table.index thead,
	table.data  tbody,
	table.index tbody {
		border-bottom: 2px solid;
	}

	table.data colgroup,
	table.index colgroup {
		border-left: 2px solid;
	}

	table.data  tbody th:first-child,
	table.index tbody th:first-child  {
		border-right: 2px solid;
		border-top: 1px solid silver;
		padding-right: 1em;
	}

	table.data th[colspan],
	table.data td[colspan] {
		text-align: center;
	}

	table.complex.data th,
	table.complex.data td {
		border: 1px solid silver;
		text-align: center;
	}

	table.data.longlastcol td:last-child,
	table.data td.long {
	 vertical-align: baseline;
	 text-align: left;
	}

	table.data img {
		vertical-align: middle;
	}


/*
Alternate table alignment rules

	table.data,
	table.index {
		text-align: center;
	}

	table.data  thead th[scope="row"],
	table.index thead th[scope="row"] {
		text-align: right;
	}

	table.data  tbody th:first-child,
	table.index tbody th:first-child  {
		text-align: right;
	}

Possible extra rowspan handling

	table.data  tbody th[rowspan]:not([rowspan='1']),
	table.index tbody th[rowspan]:not([rowspan='1']),
	table.data  tbody td[rowspan]:not([rowspan='1']),
	table.index tbody td[rowspan]:not([rowspan='1']) {
		border-left: 1px solid silver;
	}

	table.data  tbody th[rowspan]:first-child,
	table.index tbody th[rowspan]:first-child,
	table.data  tbody td[rowspan]:first-child,
	table.index tbody td[rowspan]:first-child{
		border-left: 0;
		border-right: 1px solid silver;
	}
*/

/******************************************************************************/
/*                                  Indices                                   */
/******************************************************************************/


/** Table of Contents *********************************************************/

	.toc a {
		/* More spacing; use padding to make it part of the click target. */
		padding-top: 0.1rem;
		/* Larger, more consistently-sized click target */
		display: block;
		/* Reverse color scheme */
		color: black;
		border-color: #3980B5;
		border-bottom-width: 3px !important;
		margin-bottom: 0px !important;
	}
	.toc a:visited {
		border-color: #054572;
	}
	.toc a:not(:focus):not(:hover) {
		/* Allow colors to cascade through from link styling */
		border-bottom-color: transparent;
	}

	.toc, .toc ol, .toc ul, .toc li {
		list-style: none; /* Numbers must be inlined into source */
		/* because generated content isn't search/selectable and markers can't do multilevel yet */
		margin:  0;
		padding: 0;
		line-height: 1.1rem; /* consistent spacing */
	}

	/* ToC not indented until third level, but font style & margins show hierarchy */
	.toc > li             { font-weight: bold;   }
	.toc > li li          { font-weight: normal; }
	.toc > li li li       { font-size:   95%;    }
	.toc > li li li li    { font-size:   90%;    }
	.toc > li li li li .secno { font-size: 85%; }
	.toc > li li li li li { font-size:   85%;    }
	.toc > li li li li li .secno { font-size: 100%; }

	/* @supports not (display:grid) { */
		.toc > li             { margin: 1.5rem 0;    }
		.toc > li li          { margin: 0.3rem 0;    }
		.toc > li li li       { margin-left: 2rem;   }

		/* Section numbers in a column of their own */
		.toc .secno {
			float: left;
			width: 4rem;
			white-space: nowrap;
		}

		.toc li {
			clear: both;
		}

		:not(li) > .toc              { margin-left:  5rem; }
		.toc .secno                  { margin-left: -5rem; }
		.toc > li li li .secno       { margin-left: -7rem; }
		.toc > li li li li .secno    { margin-left: -9rem; }
		.toc > li li li li li .secno { margin-left: -11rem; }

		/* Tighten up indentation in narrow ToCs */
		@media (max-width: 30em) {
			:not(li) > .toc              { margin-left:  4rem; }
			.toc .secno                  { margin-left: -4rem; }
			.toc > li li li              { margin-left:  1rem; }
			.toc > li li li .secno       { margin-left: -5rem; }
			.toc > li li li li .secno    { margin-left: -6rem; }
			.toc > li li li li li .secno { margin-left: -7rem; }
		}
	/* } */

	@supports (display:grid) {
		/* Use #toc over .toc to override non-@supports rules. */
		#toc {
			display: grid;
			align-content: start;
			grid-template-columns: auto 1fr;
			grid-column-gap: 1rem;
			column-gap: 1rem;
			grid-row-gap: .6rem;
			row-gap: .6rem;
		}
		#toc h2 {
			grid-column: 1 / -1;
			margin-bottom: 0;
		}
		#toc ol,
		#toc li,
		#toc a {
			display: contents;
			/* Switch <a> to subgrid when supported */
		}
		#toc span {
			margin: 0;
		}
		#toc > .toc > li > a > span {
			/* The spans of the top-level list,
			   comprising the first items of each top-level section. */
			margin-top: 1.1rem;
		}
		#toc#toc .secno { /* Ugh, need more specificity to override base.css */
			grid-column: 1;
			width: auto;
			margin-left: 0;
		}
		#toc .content {
			grid-column: 2;
			width: auto;
			margin-right: 1rem;
		}
		#toc .content:hover {
			background: rgba(75%, 75%, 75%, .25);
			border-bottom: 3px solid #054572;
			margin-bottom: -3px;
		}
		#toc li li li .content {
			margin-left: 1rem;
		}
		#toc li li li li .content {
			margin-left: 2rem;
		}
	}


/** Index *********************************************************************/

	/* Index Lists: Layout */
	ul.index       { margin-left: 0; columns: 15em; text-indent: 1em hanging; }
	ul.index li    { margin-left: 0; list-style: none; break-inside: avoid; }
	ul.index li li { margin-left: 1em }
	ul.index dl    { margin-top: 0; }
	ul.index dt    { margin: .2em 0 .2em 20px;}
	ul.index dd    { margin: .2em 0 .2em 40px;}
	/* Index Lists: Typography */
	ul.index ul,
	ul.index dl { font-size: smaller; }
	@media not print {
		ul.index li span {
			white-space: nowrap;
			color: transparent; }
		ul.index li a:hover + span,
		ul.index li a:focus + span {
			color: #707070;
		}
	}

/** Index Tables *****************************************************/
	/* See also the data table styling section, which this effectively subclasses */

	table.index {
		font-size: small;
		border-collapse: collapse;
		border-spacing: 0;
		text-align: left;
		margin: 1em 0;
	}

	table.index td,
	table.index th {
		padding: 0.4em;
	}

	table.index tr:hover td:not([rowspan]),
	table.index tr:hover th:not([rowspan]) {
		background: #f7f8f9;
	}

	/* The link in the first column in the property table (formerly a TD) */
	table.index th:first-child a {
		font-weight: bold;
	}

/******************************************************************************/
/*                                    Print                                   */
/******************************************************************************/

	@media print {
		/* Pages have their own margins. */
		html {
			margin: 0;
		}
		/* Serif for print. */
		body {
			font-family: serif;
		}
	}
	@page {
		margin: 1.5cm 1.1cm;
	}

/******************************************************************************/
/*                                    Legacy                                  */
/******************************************************************************/

	/* This rule is inherited from past style sheets. No idea what it's for. */
	.hide { display: none }



/******************************************************************************/
/*                             Overflow Control                               */
/******************************************************************************/

	.figure .caption, .sidefigure .caption, figcaption {
		/* in case figure is overlarge, limit caption to 50em */
		max-width: 50rem;
		margin-left: auto;
		margin-right: auto;
	}
	.overlarge > table {
		/* limit preferred width of table */
		max-width: 50em;
		margin-left: auto;
		margin-right: auto;
	}

	@media (min-width: 55em) {
		.overlarge {
			margin-left: calc(13px + 26.5rem - 50vw);
			margin-right: calc(13px + 26.5rem - 50vw);
			max-width: none;
		}
	}
	@media screen and (min-width: 78em) {
		body:not(.toc-inline) .overlarge {
			/* 30.5em body padding 50em content area */
			margin-left: calc(40em - 50vw) !important;
			margin-right: calc(40em - 50vw) !important;
		}
	}
	@media screen and (min-width: 90em) {
		body:not(.toc-inline) .overlarge {
			/* 4em html margin 30.5em body padding 50em content area */
			margin-left: 0 !important;
			margin-right: calc(84.5em - 100vw) !important;
		}
	}

	@media not print {
		.overlarge {
			overflow-x: auto;
			/* See Lea Verou's explanation background-attachment:
			 * http://lea.verou.me/2012/04/background-attachment-local/
			 *
			background: top left  / 4em 100% linear-gradient(to right,  #ffffff, rgba(255, 255, 255, 0)) local,
			            top right / 4em 100% linear-gradient(to left, #ffffff, rgba(255, 255, 255, 0)) local,
			            top left  / 1em 100% linear-gradient(to right,  #c3c3c5, rgba(195, 195, 197, 0)) scroll,
			            top right / 1em 100% linear-gradient(to left, #c3c3c5, rgba(195, 195, 197, 0)) scroll,
			            white;
			background-repeat: no-repeat;
			*/
		}
	}
</style>
<style type="text/css">
    table, th, td {
      border: 1px solid black;
      border-collapse: collapse;
      vertical-align: top;
    }
    th, td {
      border-left: none;
      border-right: none;
      padding: 0px 10px;
    }
    th {
      text-align: center;
    }
  </style>
  <meta content="Bikeshed version c03af8da7325f5ae3f9ca742161b5d270bbce12f" name="generator">
  <link href="http://wg21.link/p1108r4" rel="canonical">
  <link href="https://isocpp.org/favicon.ico" rel="icon">
  <meta content="b516d3f07db02e3a22538aec3e1fa1d9f4bdb226" name="document-revision">
<style>/* style-md-lists */

/* This is a weird hack for me not yet following the commonmark spec
   regarding paragraph and lists. */
[data-md] > :first-child {
    margin-top: 0;
}
[data-md] > :last-child {
    margin-bottom: 0;
}</style>
<style>/* style-counters */

body {
    counter-reset: example figure issue;
}
.issue {
    counter-increment: issue;
}
.issue:not(.no-marker)::before {
    content: "Issue " counter(issue);
}

.example {
    counter-increment: example;
}
.example:not(.no-marker)::before {
    content: "Example " counter(example);
}
.invalid.example:not(.no-marker)::before,
.illegal.example:not(.no-marker)::before {
    content: "Invalid Example" counter(example);
}

figcaption {
    counter-increment: figure;
}
figcaption:not(.no-marker)::before {
    content: "Figure " counter(figure) " ";
}</style>
<style>/* style-syntax-highlighting */

.highlight:not(.idl) { background: hsl(24, 20%, 95%); }
code.highlight { padding: .1em; border-radius: .3em; }
pre.highlight, pre > code.highlight { display: block; padding: 1em; margin: .5em 0; overflow: auto; border-radius: 0; }
c-[a] { color: #990055 } /* Keyword.Declaration */
c-[b] { color: #990055 } /* Keyword.Type */
c-[c] { color: #708090 } /* Comment */
c-[d] { color: #708090 } /* Comment.Multiline */
c-[e] { color: #0077aa } /* Name.Attribute */
c-[f] { color: #669900 } /* Name.Tag */
c-[g] { color: #222222 } /* Name.Variable */
c-[k] { color: #990055 } /* Keyword */
c-[l] { color: #000000 } /* Literal */
c-[m] { color: #000000 } /* Literal.Number */
c-[n] { color: #0077aa } /* Name */
c-[o] { color: #999999 } /* Operator */
c-[p] { color: #999999 } /* Punctuation */
c-[s] { color: #a67f59 } /* Literal.String */
c-[t] { color: #a67f59 } /* Literal.String.Single */
c-[u] { color: #a67f59 } /* Literal.String.Double */
c-[cp] { color: #708090 } /* Comment.Preproc */
c-[c1] { color: #708090 } /* Comment.Single */
c-[cs] { color: #708090 } /* Comment.Special */
c-[kc] { color: #990055 } /* Keyword.Constant */
c-[kn] { color: #990055 } /* Keyword.Namespace */
c-[kp] { color: #990055 } /* Keyword.Pseudo */
c-[kr] { color: #990055 } /* Keyword.Reserved */
c-[ld] { color: #000000 } /* Literal.Date */
c-[nc] { color: #0077aa } /* Name.Class */
c-[no] { color: #0077aa } /* Name.Constant */
c-[nd] { color: #0077aa } /* Name.Decorator */
c-[ni] { color: #0077aa } /* Name.Entity */
c-[ne] { color: #0077aa } /* Name.Exception */
c-[nf] { color: #0077aa } /* Name.Function */
c-[nl] { color: #0077aa } /* Name.Label */
c-[nn] { color: #0077aa } /* Name.Namespace */
c-[py] { color: #0077aa } /* Name.Property */
c-[ow] { color: #999999 } /* Operator.Word */
c-[mb] { color: #000000 } /* Literal.Number.Bin */
c-[mf] { color: #000000 } /* Literal.Number.Float */
c-[mh] { color: #000000 } /* Literal.Number.Hex */
c-[mi] { color: #000000 } /* Literal.Number.Integer */
c-[mo] { color: #000000 } /* Literal.Number.Oct */
c-[sb] { color: #a67f59 } /* Literal.String.Backtick */
c-[sc] { color: #a67f59 } /* Literal.String.Char */
c-[sd] { color: #a67f59 } /* Literal.String.Doc */
c-[se] { color: #a67f59 } /* Literal.String.Escape */
c-[sh] { color: #a67f59 } /* Literal.String.Heredoc */
c-[si] { color: #a67f59 } /* Literal.String.Interpol */
c-[sx] { color: #a67f59 } /* Literal.String.Other */
c-[sr] { color: #a67f59 } /* Literal.String.Regex */
c-[ss] { color: #a67f59 } /* Literal.String.Symbol */
c-[vc] { color: #0077aa } /* Name.Variable.Class */
c-[vg] { color: #0077aa } /* Name.Variable.Global */
c-[vi] { color: #0077aa } /* Name.Variable.Instance */
c-[il] { color: #000000 } /* Literal.Number.Integer.Long */
</style>
<style>/* style-selflinks */

.heading, .issue, .note, .example, li, dt {
    position: relative;
}
a.self-link {
    position: absolute;
    top: 0;
    left: calc(-1 * (3.5rem - 26px));
    width: calc(3.5rem - 26px);
    height: 2em;
    text-align: center;
    border: none;
    transition: opacity .2s;
    opacity: .5;
}
a.self-link:hover {
    opacity: 1;
}
.heading > a.self-link {
    font-size: 83%;
}
li > a.self-link {
    left: calc(-1 * (3.5rem - 26px) - 2em);
}
dfn > a.self-link {
    top: auto;
    left: auto;
    opacity: 0;
    width: 1.5em;
    height: 1.5em;
    background: gray;
    color: white;
    font-style: normal;
    transition: opacity .2s, background-color .2s, color .2s;
}
dfn:hover > a.self-link {
    opacity: 1;
}
dfn > a.self-link:hover {
    color: black;
}

a.self-link::before            { content: "¶"; }
.heading > a.self-link::before { content: "§"; }
dfn > a.self-link::before      { content: "#"; }</style>
<style>/* style-autolinks */

.css.css, .property.property, .descriptor.descriptor {
    color: #005a9c;
    font-size: inherit;
    font-family: inherit;
}
.css::before, .property::before, .descriptor::before {
    content: "‘";
}
.css::after, .property::after, .descriptor::after {
    content: "’";
}
.property, .descriptor {
    /* Don't wrap property and descriptor names */
    white-space: nowrap;
}
.type { /* CSS value <type> */
    font-style: italic;
}
pre .property::before, pre .property::after {
    content: "";
}
[data-link-type="property"]::before,
[data-link-type="propdesc"]::before,
[data-link-type="descriptor"]::before,
[data-link-type="value"]::before,
[data-link-type="function"]::before,
[data-link-type="at-rule"]::before,
[data-link-type="selector"]::before,
[data-link-type="maybe"]::before {
    content: "‘";
}
[data-link-type="property"]::after,
[data-link-type="propdesc"]::after,
[data-link-type="descriptor"]::after,
[data-link-type="value"]::after,
[data-link-type="function"]::after,
[data-link-type="at-rule"]::after,
[data-link-type="selector"]::after,
[data-link-type="maybe"]::after {
    content: "’";
}

[data-link-type].production::before,
[data-link-type].production::after,
.prod [data-link-type]::before,
.prod [data-link-type]::after {
    content: "";
}

[data-link-type=element],
[data-link-type=element-attr] {
    font-family: Menlo, Consolas, "DejaVu Sans Mono", monospace;
    font-size: .9em;
}
[data-link-type=element]::before { content: "<" }
[data-link-type=element]::after  { content: ">" }

[data-link-type=biblio] {
    white-space: pre;
}</style>
 <body class="h-entry">
  <div class="head">
   <p data-fill-with="logo"></p>
   <h1 class="p-name no-ref" id="title">P1108R4<br>web_view</h1>
   <h2 class="no-num no-toc no-ref heading settled" id="subtitle"><span class="content">Published Proposal, <time class="dt-updated" datetime="2019-10-07">2019-10-07</time></span></h2>
   <div data-fill-with="spec-metadata">
    <dl>
     <dt>This version:
     <dd><a class="u-url" href="http://wg21.link/p1108r4">http://wg21.link/p1108r4</a>
     <dt>Author:
     <dd>
      <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:hfinkel@anl.gov">Hal Finkel</a> (<span class="p-org org">Argonne National Laboratory</span>)
     <dt>Audience:
     <dd>SG1, SG12, SG13, SG16, SG18
     <dt>Project:
     <dd>ISO/IEC JTC1/SC22/WG21 14882: Programming Language — C++
    </dl>
   </div>
   <div data-fill-with="warning"></div>
   <hr title="Separator for header">
  </div>
  <div class="p-summary" data-fill-with="abstract">
   <h2 class="no-num no-toc no-ref heading settled" id="abstract"><span class="content">Abstract</span></h2>
   <p>This paper proposes a web_view facility for the C++ standard library. This facility enables modern, natural, multimodal user interaction by leveraging existing web standards and technologies.</p>
  </div>
  <nav data-fill-with="table-of-contents" id="toc">
   <h2 class="no-num no-toc no-ref" id="contents">Table of Contents</h2>
   <ol class="toc" role="directory">
    <li><a href="#cl"><span class="secno">1</span> <span class="content">Change Log</span></a>
    <li><a href="#intro"><span class="secno">2</span> <span class="content">Introduction</span></a>
    <li><a href="#hist"><span class="secno">3</span> <span class="content">Some History and Graphics</span></a>
    <li>
     <a href="#faq"><span class="secno">4</span> <span class="content">FAQ</span></a>
     <ol class="toc">
      <li><a href="#q1"><span class="secno">4.1</span> <span class="content">What if we do nothing?</span></a>
      <li><a href="#q2"><span class="secno">4.2</span> <span class="content">Is this API surface small- and long-lived enough to be useful?</span></a>
      <li><a href="#q3"><span class="secno">4.3</span> <span class="content">Does this proposal require that standard-library implementations ship/maintain a web browser?</span></a>
      <li><a href="#q6"><span class="secno">4.4</span> <span class="content">Why not standardize an HTTP-server library instead of this?</span></a>
      <li><a href="#q7"><span class="secno">4.5</span> <span class="content">Should there be some integration with WebSockets?</span></a>
      <li><a href="#q8"><span class="secno">4.6</span> <span class="content">Should there be some use of executors in this library?</span></a>
      <li><a href="#q9"><span class="secno">4.7</span> <span class="content">What happens when the web_view object is destroyed?</span></a>
      <li><a href="#q4"><span class="secno">4.8</span> <span class="content">Isn’t dealing with text (in HTML, JSON, URIs, etc.) ugly, verbose, difficult, error prone, or similar?</span></a>
      <li><a href="#q5"><span class="secno">4.9</span> <span class="content">Why don’t we just standardize Qt’s API?</span></a>
     </ol>
    <li><a href="#proposal"><span class="secno">5</span> <span class="content">Proposed Interface</span></a>
    <li><a href="#example"><span class="secno">6</span> <span class="content">An Example</span></a>
    <li><a href="#word"><span class="secno">7</span> <span class="content">Very-Preliminary Wording</span></a>
    <li><a href="#ack"><span class="secno">8</span> <span class="content">Acknowledgments</span></a>
    <li>
     <a href="#references"><span class="secno"></span> <span class="content">References</span></a>
     <ol class="toc">
      <li><a href="#informative"><span class="secno"></span> <span class="content">Informative References</span></a>
     </ol>
   </ol>
  </nav>
  <main>
   <h2 class="heading settled" data-level="1" id="cl"><span class="secno">1. </span><span class="content">Change Log</span><a class="self-link" href="#cl"></a></h2>
   <ul>
    <li data-md>
     <p>r4: Based on the feedback from Cologne, and afterward, significant updates: use u8string instead of string, set_uri_scheme_handler -> add_uri_scheme_handler, remove set_close_handler, run_script -> invoke,request_close -> close, wait changes, native-handle types, reduced standard list.</p>
    <li data-md>
     <p>r3: Based on the discussions in Cologne, many updates (added links to Mozilla API, use <code class="highlight"><c- o>&lt;</c-><c- n>format</c-><c- o>></c-></code>, etc.)</p>
    <li data-md>
     <p>r2: Based on the SG13 discussion in San Diego, added some comments on deployment options and process separation.</p>
    <li data-md>
     <p>r1: Added discussion of Qt. Added links to public discussion threads in the acknowledgments.</p>
   </ul>
   <h2 class="heading settled" data-level="2" id="intro"><span class="secno">2. </span><span class="content">Introduction</span><a class="self-link" href="#intro"></a></h2>
   <p>Standard C++ should enable modern, natural, multimodal user interaction in order for a facility to be broadly useful for application development. Reality is that most users do not interact with applications using a command prompt (i.e., console I/O), but rather, use some graphical user interface. The C++ standard, however, provides no useful facilities in this regard, and as a result, users either need to make use of system-specific APIs, third-party libraries, or move to a different programming language. Moreover, these interactions require both input and output facilities, where output includes 2D graphics, 3D graphics, text rendering, dialog elements, and there are many forms of input devices (especially when accessibility-related technologies are considered). While I believe that the authors of <a data-link-type="biblio" href="#biblio-p0267r7">[P0267R7]</a>, and others, have made a commendable effort in the 2D-graphics area, down-scoping the problem to 2D graphics fails to address the underlying requirement of enabling user interaction through modern interfaces.</p>
   <p>Unfortunately, this committee has neither the time nor the expertise to address this problem by directly creating some sufficiently-comprehensive API. Specifically, this is the problem
addressed by web standards (i.e., HTML, CSS, SVG, and so on), those are in-turn built on many efforts in graphics (and many other areas), and clearly we cannot foster a comparable effort in this space in this
committee. The only feasible way forward is to reach out to the large and vibrant community tackling this issue, creating portable standards in this space, and make direct use of their efforts.</p>
   <p>Walking this path to its logical conclusion leads to an API providing a window into which a C++ program can inject web content (along with some callbacks to provide data, and possibly, handle some other events
directly).</p>
   <h2 class="heading settled" data-level="3" id="hist"><span class="secno">3. </span><span class="content">Some History and Graphics</span><a class="self-link" href="#hist"></a></h2>
   <p>After a long and interestingly-introspective graphics evening session in Rapperswil, we did not have consensus to move forward in the 2D graphics space. Nevertheless, this is an important area (and see sections 4 and 5 of <a data-link-type="biblio" href="#biblio-p0939r0">[P0939R0]</a>), wide interest remains, and in this paper I propose taking a different approach from those previously discussed. In particular, I propose adding a web_view class to the standard library. I view this as taking the path represented by <a data-link-type="biblio" href="#biblio-p1062r0">[P1062R0]</a> to its logical conclusion. This represents, in my view, both the best approach, and the only practical approach, we can take to enable useful graphical user interaction in standard C++. In addition, graphics is not enough. We need to enable modern, natural, multimodal user interaction in order for a facility to be broadly useful for application development.</p>
   <p>I believe that:</p>
   <ol>
    <li data-md>
     <p>The underlying use case, which is unfortunately not well described as "2D Graphics", is important.</p>
    <li data-md>
     <p>The underlying approach of <a data-link-type="biblio" href="#biblio-p1062r0">[P1062R0]</a>, by making use of outside standards (i.e., SVG), embraces the right philosophical approach to improving standard C++ in this regard.</p>
   </ol>
   <p>This proposal was reviewed by SG13 is Cologne:</p>
   <p>We encourage further work on this paper:</p>
   <p>SF 	F 	N 	A 	SA
3 	7 	5 	0 	0</p>
   <p>And was reviewed in LEWGI:</p>
   <p>We should promise more committee time to P1108 knowing that our time is scarce and this will leave less time for other work:</p>
   <p>SF 	F 	N 	A 	SA
4 	7 	5 	0 	1</p>
   <p>This proposal has also been reviewed by SG12, SG1, and SG16.</p>
   <h2 class="heading settled" data-level="4" id="faq"><span class="secno">4. </span><span class="content">FAQ</span><a class="self-link" href="#faq"></a></h2>
   <h3 class="heading settled" data-level="4.1" id="q1"><span class="secno">4.1. </span><span class="content">What if we do nothing?</span><a class="self-link" href="#q1"></a></h3>
   <p>If we do nothing then standard C++ will continue to lack a way to create applications with modern user interfaces.</p>
   <p>That having been said, one can imagine a future in which WebAssembly standardizes some interface to the DOM (document object model) and other relevant state for WebAssembly applications running within a web-content engine, and most operating systems providing a way to launch WebAssembly applications within some otherwise-standalone web-content environment. In such a future, C++ applications, compiled to WebAssembly, might have a platform-specific, but portable, way to provide a modern user interface.</p>
   <p>While there is a desire for WebAssembly to provide access to the DOM (and other web APIs), see <a href="https://webassembly.org/docs/future-features/">WebAssembly Future Features</a> and <a href="https://github.com/WebAssembly/proposals/issues/16">WebAssembly Proposal Issue 16</a>, and there already exist packages providing functionality along these lines (e.g., <a href="https://mbasso.github.io/asm-dom/">asm-dom</a>), it is unclear whether this will provide a sufficient solution for the C++ ecosystem at large. For one thing, WebAssembly applications may never truly match the performance of applications compiled directly for the underlying hardware. Such applications also might not be able to access necessary system services directly.</p>
   <h3 class="heading settled" data-level="4.2" id="q2"><span class="secno">4.2. </span><span class="content">Is this API surface small- and long-lived enough to be useful?</span><a class="self-link" href="#q2"></a></h3>
   <p>To get some idea of what this space looks like currently, I recommend looking at:</p>
   <ul>
    <li data-md>
     <p><a href="https://webkitgtk.org/reference/webkit2gtk/stable/">The WebKit (WebKitGTK+) API</a></p>
    <li data-md>
     <p><a href="https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa752127%28v%3dvs.85%29">The Internet Explorer IWebBrowser2 API</a></p>
    <li data-md>
     <p><a href="https://developer.apple.com/documentation/webkit">The macOS/iOS WebKit API</a></p>
    <li data-md>
     <p><a href="https://developer.android.com/reference/android/webkit/WebView">The Android WebView API</a></p>
    <li data-md>
     <p><a href="https://developer.mozilla.org/en-US/docs/Mozilla/Gecko/Embedding_Mozilla">The Mozilla (Gecko) API</a></p>
   </ul>
   <p>There are a number of concepts exposed in these APIs, including things like sandboxing parameters, which seem likely be too dynamic to reasonably standardize. We’d be relying on the library to provide "reasonable defaults" in many cases. That having been said, as with our Unicode support in standard C++, our API surface could increase over time. To be useful, we’ll need to require support for a large number external standards (i.e., [X]HTML, CSS, SVG, ECMAScript, and possibly others). Our three-year release cycle is likely sufficient to maintain a proper list of such standards, but it’s still a large list, and to be clear, the transitive closure of this list is huge.</p>
   <p>Nevertheless, surveying the current implementations has convinced me that an interface along the lines of that proposed here is appropriate for standardization, at least in the sense that, while broadly useful, using these services from a C++ application today requires difficult-to-get-right platform-specific code. Moving that burden to C++ library implementers, as a result, makes sense. In addition, it should be possible to create production applications using this facility that meet modern user expectations across many different kinds of devices and platforms.</p>
   <h3 class="heading settled" data-level="4.3" id="q3"><span class="secno">4.3. </span><span class="content">Does this proposal require that standard-library implementations ship/maintain a web browser?</span><a class="self-link" href="#q3"></a></h3>
   <p>I think that it’s important that we think of this interface as one exposing underlying platform capabilities, not as one requiring an implementation shipped as part of the C++ standard library. Required security and functionality updates on many platforms for web-content support may be far more frequent than updates to the C++ standard library, and a web_view in the C++ standard library should automatically use this frequently-updated web-content software.</p>
   <p>I don’t believe that we can require all C++ implementations, not even all non-freestanding C++ implementations, to provide a web-content interface. As a result, it must be legal for an implementation to stub out the implementation of web_view where it cannot be reasonably supported. Nevertheless, given currently-shipping web-browser implementations, we can provide a succinct API that ties C++ into the most-vibrant standards-driven ecosystem in this space.</p>
   <h3 class="heading settled" data-level="4.4" id="q6"><span class="secno">4.4. </span><span class="content">Why not standardize an HTTP-server library instead of this?</span><a class="self-link" href="#q6"></a></h3>
   <p>There are three reasons why standardizing an HTTP-server library might not address the same set of use cases as this proposal.</p>
   <p>First, it does not address how to cause the web content to be displayed to the user. An external web browser might be launched and directed to some port on localhost opened by the application, but this might not provide the same look/behaviors as a native application (e.g., the name of the web browser might be visible, the localhost URL might be visible, there might not be a robust way to detect that the user closed the interface, it might appear to the user as through two applications are running, and so on). Some of these issues can be mitigated today using certain web browsers (e.g., using Chrome with the --app flag), but this usage mode for a web browser, which only addresses some of these concerns, is not universally supported today.</p>
   <p>Second, it might not be possible to create a robust, secure, high-performance library without exposing protocol-level details on the interface, and doing that might create a library interface with too short of a useful lifetime. For one thing, the HTTP landscape is evolving relatively quickly: arguably, such a library should support HTTP/2 (SPDY), or even HTTP/3 (QUIC), and should certainly support WebSockets (<a data-link-type="biblio" href="#biblio-rfc6455">[rfc6455]</a>) (which is a layered on top of HTTP). TLS support seems like a necessary feature, which immediately implies exposing functionality related to certificate management and validation. Handling of content negotiation, cookies, and many other facets of the underlying protocol would likely need to be exposed as well. It might not be possible for us to standardize an interface here that exposes a sufficient amount of detail to constitute a high-quality implementation and yet remain useful over an extended period as the technology changes.</p>
   <p>Third, providing an HTTP server is stepping away from the benefits of wrapping a system service, as this proposal does, and towards embedding a significant amount of functionality within the C++ standard library itself. From a implementation-complexity standpoint, and when considering the necessary upgrade times and timescales for responding to security issues, this looks much less appealing.</p>
   <h3 class="heading settled" data-level="4.5" id="q7"><span class="secno">4.5. </span><span class="content">Should there be some integration with WebSockets?</span><a class="self-link" href="#q7"></a></h3>
   <p>Once we have networking support, it might be possible to specify some kind of stream object that can be used other networking facilities, some way to generate such a stream, and some way to get the name of the stream for use in the web content. This seems like a reasonable extension to what is proposed here, and WebSockets are widely supported, although it does depart from the model of wrapping existing system services (as with the standardized HTTP-server question).</p>
   <h3 class="heading settled" data-level="4.6" id="q8"><span class="secno">4.6. </span><span class="content">Should there be some use of executors in this library?</span><a class="self-link" href="#q8"></a></h3>
   <p>Yes. Once we have executors, the interface proposed here should use them to specify where the URI-scheme handlers are run.</p>
   <h3 class="heading settled" data-level="4.7" id="q9"><span class="secno">4.7. </span><span class="content">What happens when the web_view object is destroyed?</span><a class="self-link" href="#q9"></a></h3>
   <p>In the current proposal, the destructor blocks until any callbacks have finished executing, and then it closes the window. This is expected to be the easiest-to-use behavior (and aims to avoid undefined behavior). There was an explicit vote in SG1 in Cologne on this aspect of the interface:</p>
   <p>Destructing a web_view that is not closed (with an is_closed() member) should be UB</p>
   <p>SF F N A SA</p>
   <p>1 1 6 4 0</p>
   <h3 class="heading settled" data-level="4.8" id="q4"><span class="secno">4.8. </span><span class="content">Isn’t dealing with text (in HTML, JSON, URIs, etc.) ugly, verbose, difficult, error prone, or similar?</span><a class="self-link" href="#q4"></a></h3>
   <p>Interacting with HTML, etc. is cumbersome in C++ without additional libraries (especially as presented in the example in this paper). I fully expect that, if we decide to go down this route, additional utilities and abstractions will be added to go along with it. Also, even with only the presented interface, I can certainly imagine constructing a program with mostly-static HTML input combined with some kind of reactive JavaScript library (e.g., <a href="https://vuejs.org/">Vue.js</a>) that’s reasonably clean (at least in the sense that it does not involve the gratuitous composition of markup text in C++, although it might involve use of JavaScript injection to update values).</p>
   <h3 class="heading settled" data-level="4.9" id="q5"><span class="secno">4.9. </span><span class="content">Why don’t we just standardize Qt’s API?</span><a class="self-link" href="#q5"></a></h3>
   <p>Qt is not the only framework in this space, but it seems representative. From http://doc.qt.io/qt-5/classes.html, there are 1,594 classes in the Qt 5 API. From http://doc.qt.io/qt-5/functions.html, there are 12,984 functions. Dealing with such a large API seems impractical for our committee process, and frankly, this still seems impractical even if we were to strip this down significantly. Specifically, I don’t really see the committee taking a hands-off approach to the content of the interface. Even if we could start with the text of Qt’s documentation, we’d need to make sure that each class and function were specified in sufficient detail to allow for an independent (clean-room) implementation. I’m sure that suggestions would be made to change aspects of the interface to better expose capabilities of different vendors' underlying implementations, and future systems, and these would be discussed.</p>
   <p>It has been further suggested that I look at QML/QtQuick, instead of QtWidgets, as a point of comparison. However, it’s not clear why standardizing something which looks like QML/QtQuick would be more useful than using web content. QML also uses JavaScript. Also, the discussion of "Quick Controls 1 vs. Quick Controls 2" (http://doc.qt.io/qt-5/qtquickcontrols2-differences.html) seems to be provide some non-trivial choices around desktop vs. mobile development. This could be a viable path for a standardization effort. It would, however, almost certainly invite design discussions around the API, the controls, etc. (because we can’t hand that off to another standard, so we’d need to do that part ourselves), and we’d need a small-enough API surface for that to be practical.</p>
   <h2 class="heading settled" data-level="5" id="proposal"><span class="secno">5. </span><span class="content">Proposed Interface</span><a class="self-link" href="#proposal"></a></h2>
<pre class="highlight"><c- k>namespace</c-> <c- n>std</c-> <c- p>{</c->
  <c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
  <c- n>concept</c-> <c- n>URISchemeHandler</c-> <c- o>=</c-> <c- n>requires</c-><c- p>(</c-><c- n>T</c-> <c- n>handler</c-><c- p>,</c-> <c- k>const</c-> <c- n>std</c-><c- o>::</c-><c- n>u8string</c-> <c- o>&amp;</c-><c- n>uri</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>ostream</c-> <c- o>&amp;</c-><c- n>os</c-><c- p>)</c-> <c- p>{</c->
    <c- p>{</c-> <c- n>handler</c-><c- p>(</c-><c- n>uri</c-><c- p>,</c-> <c- n>os</c-><c- p>)</c-> <c- p>}</c-> <c- o>-></c-> <c- n>std</c-><c- o>::</c-><c- n>error_code</c-><c- p>;</c->
  <c- p>};</c->

  <c- k>struct</c-> <c- n>web_view</c-> <c- p>{</c->
    <c- k>using</c-> <c- n>native_handle_type</c-> <c- o>=</c-> <c- n>implementation</c-><c- o>-</c-><c- n>defined</c-><c- p>;</c-> <c- c1>// Defined as in 32.2.3.</c->
    <c- k>using</c-> <c- n>native_options_type</c-> <c- o>=</c-> <c- n>implementation</c-><c- o>-</c-><c- n>defined</c-><c- p>;</c-> <c- c1>// Defined as in 32.2.3.</c->

    <c- n>web_view</c-><c- p>(</c-><c- k>const</c-> <c- n>std</c-><c- o>::</c-><c- n>u8string</c-> <c- o>&amp;</c-><c- n>title</c-> <c- o>=</c-> <c- s>""</c-><c- p>);</c->
    <c- n>web_view</c-><c- p>(</c-><c- k>const</c-> <c- n>native_options_type</c-> <c- o>&amp;</c-><c- n>options</c-><c- p>,</c-> <c- k>const</c-> <c- n>std</c-><c- o>::</c-><c- n>u8string</c-> <c- o>&amp;</c-><c- n>title</c-> <c- o>=</c-> <c- s>""</c-><c- p>);</c->

    <c- b>void</c-> <c- nf>display_from_uri</c-><c- p>(</c-><c- k>const</c-> <c- n>std</c-><c- o>::</c-><c- n>u8string</c-> <c- o>&amp;</c-><c- n>uri</c-><c- p>);</c->

    <c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>Ret</c-><c- p>,</c-> <c- k>typename</c-><c- p>...</c-> <c- n>Args</c-><c- o>></c->
    <c- n>std</c-><c- o>::</c-><c- n>future</c-><c- o>&lt;</c-><c- n>Ret</c-><c- o>></c-> <c- n>invoke</c-><c- p>(</c-><c- k>const</c-> <c- n>std</c-><c- o>::</c-><c- n>u8string</c-> <c- o>&amp;</c-><c- n>func_name</c-><c- p>,</c-> <c- n>Args</c-><c- o>&amp;&amp;</c-><c- p>...</c-> <c- n>args</c-><c- p>);</c->

    <c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>URISchemeHandler</c-><c- o>></c->
    <c- b>void</c-> <c- n>add_uri_scheme_handler</c-><c- p>(</c-><c- k>const</c-> <c- n>std</c-><c- o>::</c-><c- n>u8string</c-> <c- o>&amp;</c-><c- n>scheme</c-><c- p>,</c-> <c- n>URISchemeHandler</c-> <c- n>handler</c-><c- p>);</c->

    <c- b>void</c-> <c- nf>wait</c-><c- p>(</c-><c- b>bool</c-> <c- n>closed</c-> <c- o>=</c-> true<c- p>);</c->
    <c- b>void</c-> <c- nf>wait</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>error_code</c-> <c- o>&amp;</c-><c- n>last_errc</c-><c- p>,</c-> <c- b>bool</c-> <c- n>closed</c-> <c- o>=</c-> true<c- p>);</c->

    <c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>Rep</c-><c- p>,</c-> <c- k>typename</c-> <c- n>Period</c-><c- o>></c->
    <c- b>bool</c-> <c- n>wait_for</c-><c- p>(</c-><c- k>const</c-> <c- n>std</c-><c- o>::</c-><c- n>chrono</c-><c- o>::</c-><c- n>duration</c-><c- o>&lt;</c-><c- n>Rep</c-><c- p>,</c-> <c- n>Period</c-><c- o>>&amp;</c-> <c- n>rel_time</c-><c- p>,</c-> <c- b>bool</c-> <c- n>closed</c-> <c- o>=</c-> true<c- p>);</c->
    <c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>Rep</c-><c- p>,</c-> <c- k>typename</c-> <c- n>Period</c-><c- o>></c->
    <c- b>bool</c-> <c- n>wait_for</c-><c- p>(</c-><c- k>const</c-> <c- n>std</c-><c- o>::</c-><c- n>chrono</c-><c- o>::</c-><c- n>duration</c-><c- o>&lt;</c-><c- n>Rep</c-><c- p>,</c-> <c- n>Period</c-><c- o>>&amp;</c-> <c- n>rel_time</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>error_code</c-> <c- o>&amp;</c-><c- n>last_errc</c-><c- p>,</c-> <c- b>bool</c-> <c- n>closed</c-> <c- o>=</c-> true<c- p>);</c->

    <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>Clock</c-><c- p>,</c-> <c- k>class</c-> <c- nc>Duration</c-><c- o>></c->
    <c- b>bool</c-> <c- n>wait_until</c-><c- p>(</c-><c- k>const</c-> <c- n>chrono</c-><c- o>::</c-><c- n>time_point</c-><c- o>&lt;</c-><c- n>Clock</c-><c- p>,</c-> <c- n>Duration</c-><c- o>>&amp;</c-> <c- n>abs_time</c-><c- p>,</c-> <c- b>bool</c-> <c- n>closed</c-> <c- o>=</c-> true<c- p>);</c->
    <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>Clock</c-><c- p>,</c-> <c- k>class</c-> <c- nc>Duration</c-><c- o>></c->
    <c- b>bool</c-> <c- n>wait_until</c-><c- p>(</c-><c- k>const</c-> <c- n>chrono</c-><c- o>::</c-><c- n>time_point</c-><c- o>&lt;</c-><c- n>Clock</c-><c- p>,</c-> <c- n>Duration</c-><c- o>>&amp;</c-> <c- n>abs_time</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>error_code</c-> <c- o>&amp;</c-><c- n>last_errc</c-><c- p>,</c-> <c- b>bool</c-> <c- n>closed</c-> <c- o>=</c-> true<c- p>);</c-> 

    <c- b>void</c-> <c- nf>close</c-><c- p>();</c->

    <c- n>native_handle_type</c-> <c- nf>native_handle</c-><c- p>();</c-> <c- c1>// Defined as in 32.2.3.</c->
  <c- p>};</c->
<c- p>}</c->
</pre>
   <p>An implementation of this interface is available from my github page: <a href="https://github.com/hfinkel/web_view">web_view</a>. This implementation uses the wxWidgets <a href="http://docs.wxwidgets.org/3.1.1/classwx_web_view.html">wxWebView</a> class which implemented in terms of the platform-native APIs listed above for IE (on Windows), WebKit (on macOS/iOS), and WebKitGTK+ (on Linux and other platforms). Qt also provides a <a href="https://doc.qt.io/qt-5.11/qtwebview-index.html">QtWebView</a>, but cannot currently fully support the proposed interface because it does not provide URI-scheme handlers. There are several others wrappers of these kinds that I found on github embedded inside of other projects (e.g., <a href="https://github.com/sreichholf/FireBreath/tree/master/src/libs/WebView">FireBreath</a>, <a href="https://github.com/caitp/TwitchSwitcher/blob/master/src/webview.cpp">TwitchSwitcher</a>, and <a href="https://github.com/sumatrapdfreader/sumatrapdf/blob/master/src/utils/HtmlWindow.cpp">SumatraPDF</a> (this one is IE-only, but see references therein for interesting details)).</p>
   <p>The proposed interface does not have a function to display a web page directly from a string (or similar). Such a facility could certainly be provided given the underlying interfaces provided by the browser APIs. However, if that page is going to contain links to further content that the application will provide, then a URI-scheme handler will be needed regardless. If the content is truly static and resides in a file, the a path to the file can be provided to the display_from_uri method. It should be noted that, as a limitation derived from current implementations, the URI scheme handlers provide a kind of virtual file-system interface, and as such, do not support POST data being provided to the handler along with the URI itself. To support that, and other protocols directly, we may need to provide an actual socket-based server to which the web_view could connect.</p>
   <p>It is important to note that the handlers, both the URI-scheme handler, and the close handler, likely must be allowed to run in a different thread from the thread that created the web_view object. For security and other reasons, many implementations will separate the web-content rendering and script execution into a separate process. The web_view interface must allow for this, and in practice, this implies that the interface should avoid fine-grained interaction between the C++ application and the web content (as, in many implementations, all such interactions are mediated by remote procedure calls (RPC), and such calls are relatively expensive). Specifically, traversing and altering the DOM (document object model) of the content of the web_view from the C++ application, even if supported by the underlying platform APIs, would not only require a larger API surface, but would likely also be an expensive API to use.</p>
   <h2 class="heading settled" data-level="6" id="example"><span class="secno">6. </span><span class="content">An Example</span><a class="self-link" href="#example"></a></h2>
   <p>Here’s an example application which uses the proposed interface. It is the test in the prototype implementation repository, and while not the simplest possible application, it makes use of all of the parts of the proposed interfaces, and moreover, makes it clear that asynchronous programming may be unavoidable in this space.</p>
<pre class="highlight"><c- cp>#include</c-> &lt;web_view>

<c- cp>#include</c-> &lt;vector>
<c- cp>#include</c-> &lt;string>
<c- cp>#include</c-> &lt;chrono>
<c- cp>#include</c-> &lt;format>
<c- k>using</c-> <c- k>namespace</c-> <c- n>std</c-><c- o>::</c-><c- n>chrono_literals</c-><c- p>;</c->

<c- b>int</c-> <c- nf>main</c-><c- p>(</c-><c- b>int</c-> <c- n>argc</c-><c- p>,</c-> <c- b>char</c-> <c- o>*</c-><c- n>argv</c-><c- p>[])</c-> <c- p>{</c->
  <c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- n>std</c-><c- o>::</c-><c- n>string</c-><c- o>></c-> <c- n>args</c-><c- p>(</c-><c- n>argv</c-><c- p>,</c-> <c- n>argv</c-> <c- o>+</c-> <c- n>argc</c-><c- p>);</c->

  <c- n>std</c-><c- o>::</c-><c- n>web_view</c-> <c- n>w</c-><c- p>(</c-><c- s>"web_view test app"</c-><c- p>);</c->
  <c- n>w</c-><c- p>.</c-><c- n>add_uri_scheme_handler</c-><c- p>(</c-><c- s>"wv"</c-><c- p>,</c-> <c- p>[</c-><c- o>&amp;</c-><c- p>](</c-><c- k>const</c-> <c- n>std</c-><c- o>::</c-><c- n>u8string</c-> <c- o>&amp;</c-><c- n>uri</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>ostream</c-> <c- o>&amp;</c-><c- n>os</c-><c- p>)</c-> <c- p>{</c->
    <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"request: "</c-> <c- o>&lt;&lt;</c-> <c- n>uri</c-> <c- o>&lt;&lt;</c-> <c- s>"</c-><c- se>\n</c-><c- s>"</c-><c- p>;</c->
    <c- n>os</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>format</c-><c- p>(</c-><c- s>"&lt;html>&lt;head>&lt;title>{0}&lt;/title>&lt;script>"</c->
                      <c- s>"function newitem() {"</c->
                        <c- s>"var node = document.createElement('li');"</c->
                        <c- s>"node.appendChild(document.createTextNode('Time has passed'));"</c->
                        <c- s>"document.getElementById('dl').appendChild(node); "</c->
                        <c- s>"var d = new Date(); d.getTime();"</c->
                      <c- s>"}"</c->
                      <c- s>"&lt;/script>&lt;/head>&lt;body>&lt;p>{0}&lt;/p>&lt;table></c-><c- se>\n</c-><c- s>"</c-><c- p>,</c-> <c- n>uri</c-><c- p>);</c->
    <c- k>for</c-> <c- p>(</c-><c- k>auto</c-> <c- o>&amp;</c-><c- nl>a</c-> <c- p>:</c-> <c- n>args</c-><c- p>)</c->
      <c- n>os</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>format</c-><c- p>(</c-><c- s>"&lt;tr>&lt;td>{}&lt;/td>&lt;/tr></c-><c- se>\n</c-><c- s>"</c-><c- p>,</c-> <c- n>a</c-><c- p>);</c-> <c- c1>// we need some kind of "to_html" utility function.</c->
    <c- n>os</c-> <c- o>&lt;&lt;</c-> <c- s>"&lt;/table>"</c-><c- p>;</c->
    <c- n>os</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>format</c-><c- p>(</c-><c- s>"&lt;p>&lt;a href=</c-><c- se>\"</c-><c- s>{}/more.html</c-><c- se>\"</c-><c- s>>more&lt;/a>&lt;/p>"</c-><c- p>,</c-> <c- n>uri</c-><c- p>);</c->
    <c- n>os</c-> <c- o>&lt;&lt;</c-> <c- s>"&lt;ul id='dl'>&lt;/ul>"</c-><c- p>;</c->
    <c- n>os</c-> <c- o>&lt;&lt;</c-> <c- s>"&lt;/body>&lt;/html>"</c-><c- p>;</c->

    <c- k>return</c-> true<c- p>;</c->
  <c- p>});</c->

  <c- n>w</c-><c- p>.</c-><c- n>display_from_uri</c-><c- p>(</c-><c- s>"wv://first.html"</c-><c- p>);</c->

  <c- n>std</c-><c- o>::</c-><c- n>error_code</c-> <c- n>e</c-><c- p>;</c->
  <c- n>w</c-><c- p>.</c-><c- n>wait</c-><c- p>(</c->false<c- p>,</c-> <c- n>e</c-><c- p>);</c->
  <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"initial display complete: "</c-> <c- o>&lt;&lt;</c-> <c- n>e</c-> <c- o>&lt;&lt;</c-> <c- s>"</c-><c- se>\n</c-><c- s>"</c-><c- p>;</c->

  <c- k>while</c-> <c- p>(</c-><c- o>!</c-><c- n>w</c-><c- p>.</c-><c- n>wait_for</c-><c- p>(</c-><c- mi>2000</c-><c- n>ms</c-><c- p>))</c-> <c- p>{</c->
    <c- k>auto</c-> <c- n>r</c-> <c- o>=</c-> <c- n>w</c-><c- p>.</c-><c- n>invoke</c-><c- o>&lt;</c-><c- b>double</c-><c- o>></c-><c- p>(</c-><c- s>"newitem"</c-><c- p>);</c->
    <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"got from script: "</c-> <c- o>&lt;&lt;</c-> <c- n>r</c-><c- p>.</c-><c- n>get</c-><c- p>()</c-> <c- o>&lt;&lt;</c-> <c- s>"</c-><c- se>\n</c-><c- s>"</c-><c- p>;</c->
  <c- p>}</c->

  <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"web_view closed</c-><c- se>\n</c-><c- s>"</c-><c- p>;</c->

  <c- k>return</c-> <c- mi>0</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <h2 class="heading settled" data-level="7" id="word"><span class="secno">7. </span><span class="content">Very-Preliminary Wording</span><a class="self-link" href="#word"></a></h2>
   <p>Header <code class="highlight"><c- o>&lt;</c-><c- n>web_view</c-><c- o>></c-></code> synopsis [<strong>web_view.syn</strong>]:</p>
   <p>
    The header 
    <web_view> defines a class for providing a web-content-driven interface for the purpose of external user interaction.</web_view>
   </p>
   <blockquote>
<pre class="highlight"><c- k>namespace</c-> <c- n>std</c-> <c- p>{</c->
  <c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
  <c- n>concept</c-> <c- n>URISchemeHandler</c-> <c- o>=</c-> <c- n>requires</c-><c- p>(</c-><c- n>T</c-> <c- n>handler</c-><c- p>,</c-> <c- k>const</c-> <c- n>std</c-><c- o>::</c-><c- n>u8string</c-> <c- o>&amp;</c-><c- n>uri</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>ostream</c-> <c- o>&amp;</c-><c- n>os</c-><c- p>)</c-> <c- p>{</c->
    <c- p>{</c-> <c- n>handler</c-><c- p>(</c-><c- n>uri</c-><c- p>,</c-> <c- n>os</c-><c- p>)</c-> <c- p>}</c-> <c- o>-></c-> <c- n>std</c-><c- o>::</c-><c- n>error_code</c-><c- p>;</c->
  <c- p>};</c->

  <c- k>class</c-> <c- nc>web_view</c-><c- p>;</c->
<c- p>}</c->
</pre>
   </blockquote>
   <p>class web_view [<strong>web_view</strong>]</p>
   <blockquote>
<pre class="highlight"><c- k>class</c-> <c- nc>web_view</c-> <c- p>{</c->
  <c- p>...</c-> <c- c1>// see above</c->
<c- p>};</c->
</pre>
   </blockquote>
   <p>Each web_view class instance represents an independent, asynchronous web-content interface. The provided web_view shall support content complying with the <a data-link-type="biblio" href="#biblio-html5">[HTML5]</a>, <a data-link-type="biblio" href="#biblio-png">[PNG]</a>, and <a data-link-type="biblio" href="#biblio-ecmascript">[ECMAScript]</a> standards.</p>
   <p>[ <em>Note</em>:</p>
   <p>Implementations are encouraged to support the latest <a href="https://spec.whatwg.org/">WHATWG living standards</a>, <a data-link-type="biblio" href="#biblio-wai-aria">[wai-aria]</a>, <a data-link-type="biblio" href="#biblio-webgl">[WebGL]</a>, <a data-link-type="biblio" href="#biblio-webrtc">[webrtc]</a>, <a data-link-type="biblio" href="#biblio-webvtt1">[webvtt1]</a>, <a data-link-type="biblio" href="#biblio-svg11">[SVG11]</a>, CSS standards, DOM standards, and otherwise maximize compatibility with other implementations (see, e.g., <a href="https://caniuse.com/">Can I use...</a> )</p>
   <p>-- <em>end note</em> ]</p>
   <p>All std::u8string objects used with std::web_view must contain well-formed UTF-8 data.</p>
   <p>The destructor blocks until all URI-scheme handlers have returned. These handlers are allowed to call member functions on a web_view object, even if another thread has concurrently started execution of the destructor.</p>
   <p>web_view member functions [<strong>web_view.members</strong>]</p>
   <blockquote>
<pre class="highlight"><c- n>web_view</c-><c- p>(</c-><c- k>const</c-> <c- n>std</c-><c- o>::</c-><c- n>u8string</c-> <c- o>&amp;</c-><c- n>title</c-> <c- o>=</c-> <c- s>""</c-><c- p>);</c-><c- n>web_view</c-><c- p>(</c-><c- k>const</c-> <c- n>native_options_type</c-> <c- o>&amp;</c-><c- n>options</c-><c- p>,</c-> <c- k>const</c-> <c- n>std</c-><c- o>::</c-><c- n>u8string</c-> <c- o>&amp;</c-><c- n>title</c-> <c- o>=</c-> <c- s>""</c-><c- p>);</c-></pre>
   </blockquote>
   <p><em>Effects</em>: Constructs an object of the class web_view with the specified title.</p>
   <p>[ <em>Note</em>:</p>
   <p>The title should be used by the implementation to associate a name with the web content’s interface consistent with how that implementation generally displays the name of an interactive application. For example, on implementations that display graphical windows with title bars, the provided title, followed by a ": ", may be prepended to any title provided by the web content itself for the purpose of setting the text displayed in the title bar. The intent is that, from the user’s perspective, the title sets the name of the application associated with the web content’s interface.</p>
   <p>-- <em>end note</em> ]</p>
   <p>If the implementation defines a native_options_type, then the corresponding overload shall be provided.</p>
   <blockquote>
<pre class="highlight"><c- n>std</c-><c- o>::</c-><c- n>future</c-><c- o>&lt;</c-><c- n>std</c-><c- o>::</c-><c- n>error_code</c-><c- o>></c-> <c- n>display_from_uri</c-><c- p>(</c-><c- k>const</c-> <c- n>std</c-><c- o>::</c-><c- n>u8string</c-> <c- o>&amp;</c-><c- n>uri</c-><c- p>);</c-></pre>
   </blockquote>
   <p><em>Effects</em>: Causes the top-level web content to be replaced with content loaded from the provided URI. The implementation shall support the URI format specified in <a data-link-type="biblio" href="#biblio-rfc3986">[rfc3986]</a>.</p>
   <p><em>Returns</em>: A future containing the error code describing the final status of the request. It is implementation defined at what point during the content-loading process the error status is determined. If resources are unavailable to display the requested content, then an error should be set in the returned future. The implementation shall not wait indefinitely for necessary resources to become available before setting the final error status.</p>
   <p>[<em>Note</em>:</p>
   <p>The implementation should handle this function as a top-level navigation request. All state associated with web content previously displayed should be rendered inaccessible to the content loaded as a result of calling this function. If the previous content caused additional windows to be opened, those windows should be closed.</p>
   <p>-- <em>end note</em> ]</p>
   <blockquote>
<pre class="highlight"><c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>Ret</c-><c- p>,</c-> <c- k>typename</c-><c- p>...</c-> <c- n>Args</c-><c- o>></c-><c- n>std</c-><c- o>::</c-><c- n>future</c-><c- o>&lt;</c-><c- n>Ret</c-><c- o>></c-> <c- n>invoke</c-><c- p>(</c-><c- k>const</c-> <c- n>std</c-><c- o>::</c-><c- n>u8string</c-> <c- o>&amp;</c-><c- n>fun_name</c-><c- p>,</c-> <c- n>Args</c-><c- o>&amp;&amp;</c-><c- p>...</c-> <c- n>args</c-><c- p>);</c-></pre>
   </blockquote>
   <p><em>Effects</em>: The implementation shall execute the named function in the context of currently-displayed web content. The named function may refer to a <a data-link-type="biblio" href="#biblio-ecmascript">[ECMAScript]</a> script function in the context of the current web content or any other function that might be made available in an implementation-defined manner. The implementation may define limits on the size of the provided arguments and the execution time of the script.</p>
   <p><em>Returns</em>: The result of the script shall be converted to the type Ret and set in the returned future. If the execution of the requested function, or any of the necessary type conversions are not possible, then the future’s associated shared state will be abandoned.</p>
   <p>The intent here is that some mapping between JSON entities and types will be specified, and some type-traits and/or reflection capability will be used to enable conversion between user-defined types and JSON entities. JSON serialization libraries are a common use cases for reflection schemes (see, e.g., <a href="http://jrruethe.github.io/blog/2015/05/21/boost-fusion-json-serializer/">Boost Fusion Json Serializer</a>, <a href="https://www.boost.org/doc/libs/1_62_0/libs/hana/doc/html/index.html#tutorial-introspection-json">Boost.Hana JSON example</a>). A similar mapping scheme must be used for the provided arguments.</p>
   <p>The intent here is to support invoking ECMAScript functions while allowing for future enhancements (e.g., some kind of exported WebAssembly functions).</p>
   <p>It is expected that, for security reasons, implementations might restrict or disable this interface for web content provided by some remote sources.</p>
   <blockquote>
<pre class="highlight"><c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>URISchemeHandler</c-><c- o>></c-><c- b>void</c-> <c- n>add_uri_scheme_handler</c-><c- p>(</c-><c- k>const</c-> <c- n>std</c-><c- o>::</c-><c- n>u8string</c-> <c- o>&amp;</c-><c- n>scheme</c-><c- p>,</c-> <c- n>URISchemeHandler</c-> <c- n>handler</c-><c- p>);</c-></pre>
   </blockquote>
   <p><em>Effects</em>: Registers the provided callable object to handle the provided URI scheme. When requests are generated to URIs with the provided scheme, the function-call operator of the provided object is invoked. The handler is provided with the full URI requested and a reference to a std::ostream into which the requested data should be stored. If an error is encountered, an appropriate error code should be returned. Methods on the provided handler object may be simultaneously called on threads other than the thread calling this function. Such calls need not be synchronized with each other.</p>
   <blockquote>
<pre class="highlight">    <c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>Rep</c-><c- p>,</c-> <c- k>typename</c-> <c- n>Period</c-><c- o>></c-><c- b>bool</c-> <c- n>wait_for</c-><c- p>(</c-><c- k>const</c-> <c- n>std</c-><c- o>::</c-><c- n>chrono</c-><c- o>::</c-><c- n>duration</c-><c- o>&lt;</c-><c- n>Rep</c-><c- p>,</c-> <c- n>Period</c-><c- o>>&amp;</c-> <c- n>rel_time</c-><c- p>,</c-> <c- b>bool</c-> <c- n>closed</c-> <c- o>=</c-> true<c- p>);</c->
<c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>Rep</c-><c- p>,</c-> <c- k>typename</c-> <c- n>Period</c-><c- o>></c->
<c- b>bool</c-> <c- n>wait_for</c-><c- p>(</c-><c- k>const</c-> <c- n>std</c-><c- o>::</c-><c- n>chrono</c-><c- o>::</c-><c- n>duration</c-><c- o>&lt;</c-><c- n>Rep</c-><c- p>,</c-> <c- n>Period</c-><c- o>>&amp;</c-> <c- n>rel_time</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>error_code</c-> <c- o>&amp;</c-><c- n>last_errc</c-><c- p>,</c-> <c- b>bool</c-> <c- n>closed</c-> <c- o>=</c-> true<c- p>);</c-></pre>
   </blockquote>
   <p><em>Effects</em>: Waits until the web content’s interface becomes irrevocably unusable, or if closed is false, until the top-level web-content loading is complete, or the specified time interval has elapsed. If the return value is true, then last_errc shall be set.</p>
   <p><em>Returns</em>: <code class="highlight">true</code> if web content’s interface has become irrevocably unusable, or if closed is false, if the top-level web-content loading is complete.</p>
   <p><em>Throws</em>: Timeout-related exceptions (32.2.4).</p>
   <blockquote>
<pre class="highlight">    <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>Clock</c-><c- p>,</c-> <c- k>class</c-> <c- nc>Duration</c-><c- o>></c-><c- b>bool</c-> <c- n>wait_until</c-><c- p>(</c-><c- k>const</c-> <c- n>chrono</c-><c- o>::</c-><c- n>time_point</c-><c- o>&lt;</c-><c- n>Clock</c-><c- p>,</c-> <c- n>Duration</c-><c- o>>&amp;</c-> <c- n>abs_time</c-><c- p>,</c-> <c- b>bool</c-> <c- n>closed</c-> <c- o>=</c-> true<c- p>);</c->
<c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>Clock</c-><c- p>,</c-> <c- k>class</c-> <c- nc>Duration</c-><c- o>></c->
<c- b>bool</c-> <c- n>wait_until</c-><c- p>(</c-><c- k>const</c-> <c- n>chrono</c-><c- o>::</c-><c- n>time_point</c-><c- o>&lt;</c-><c- n>Clock</c-><c- p>,</c-> <c- n>Duration</c-><c- o>>&amp;</c-> <c- n>abs_time</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>error_code</c-> <c- o>&amp;</c-><c- n>last_errc</c-><c- p>,</c-> <c- b>bool</c-> <c- n>closed</c-> <c- o>=</c-> true<c- p>);</c-> </pre>
   </blockquote>
   <p><em>Effects</em>: Waits until the web content’s interface becomes irrevocably unusable, or if closed is false, until the top-level web-content loading is complete, or the specified time has been reached. If the return value is true, then last_errc shall be set.</p>
   <p><em>Returns</em>: <code class="highlight">true</code> if web content’s interface has become irrevocably unusable, or if closed is false, if the top-level web-content loading is complete.</p>
   <p><em>Throws</em>: Timeout-related exceptions (32.2.4).</p>
   <blockquote>
<pre class="highlight"><c- b>void</c-> <c- nf>wait</c-><c- p>(</c-><c- b>bool</c-> <c- n>closed</c-> <c- o>=</c-> true<c- p>);</c-><c- b>void</c-> <c- nf>wait</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>error_code</c-> <c- o>&amp;</c-><c- n>last_errc</c-><c- p>,</c-> <c- b>bool</c-> <c- n>closed</c-> <c- o>=</c-> true<c- p>);</c-></pre>
   </blockquote>
   <p><em>Effects</em>: Waits until the web content’s interface becomes irrevocably unusable, or if closed is false, until the top-level web-content loading is complete.</p>
   <p><em>Throws</em>: Timeout-related exceptions (32.2.4).</p>
   <p>Concurrent invocation of wait is allowed.</p>
   <blockquote>
<pre class="highlight"><c- b>void</c-> <c- nf>close</c-><c- p>();</c-></pre>
   </blockquote>
   <p><em>Effects</em>: Requests, asynchronously, that the web content’s interface become irrevocably unusable.</p>
   <h2 class="heading settled" data-level="8" id="ack"><span class="secno">8. </span><span class="content">Acknowledgments</span><a class="self-link" href="#ack"></a></h2>
   <p>I’d like to thank JF Bastien, Botond Ballo, Jeffrey Yasskin, Mike Spertus, Bryce Lelbach, Vinnie Falco, and Chandler Carruth for feedback and suggestions.</p>
   <p>Some public discussion is available on <a href="https://www.reddit.com/r/cpp/comments/900dor/stdweb_view_proposal/">reddit</a>. Also, see this thread on <a href="https://groups.google.com/forum/#!topic/mozilla.dev.platform/HGjLpdUaLsI">Gecko’s list</a>.</p>
   <p>The telecon SG16 review: <a href="https://github.com/sg16-unicode/sg16-meetings#august-21st-2019">Notes</a></p>
   <p>The Argonne Leadership Computing Facility is a DOE Office of Science User Facility supported under Contract DE-AC02-06CH11357.</p>
  </main>
<script>
(function() {
  "use strict";
  var collapseSidebarText = '<span aria-hidden="true">←</span> '
                          + '<span>Collapse Sidebar</span>';
  var expandSidebarText   = '<span aria-hidden="true">→</span> '
                          + '<span>Pop Out Sidebar</span>';
  var tocJumpText         = '<span aria-hidden="true">↑</span> '
                          + '<span>Jump to Table of Contents</span>';

  var sidebarMedia = window.matchMedia('screen and (min-width: 78em)');
  var autoToggle   = function(e){ toggleSidebar(e.matches) };
  if(sidebarMedia.addListener) {
    sidebarMedia.addListener(autoToggle);
  }

  function toggleSidebar(on) {
    if (on == undefined) {
      on = !document.body.classList.contains('toc-sidebar');
    }

    /* Don’t scroll to compensate for the ToC if we’re above it already. */
    var headY = 0;
    var head = document.querySelector('.head');
    if (head) {
      // terrible approx of "top of ToC"
      headY += head.offsetTop + head.offsetHeight;
    }
    var skipScroll = window.scrollY < headY;

    var toggle = document.getElementById('toc-toggle');
    var tocNav = document.getElementById('toc');
    if (on) {
      var tocHeight = tocNav.offsetHeight;
      document.body.classList.add('toc-sidebar');
      document.body.classList.remove('toc-inline');
      toggle.innerHTML = collapseSidebarText;
      if (!skipScroll) {
        window.scrollBy(0, 0 - tocHeight);
      }
      tocNav.focus();
      sidebarMedia.addListener(autoToggle); // auto-collapse when out of room
    }
    else {
      document.body.classList.add('toc-inline');
      document.body.classList.remove('toc-sidebar');
      toggle.innerHTML = expandSidebarText;
      if (!skipScroll) {
        window.scrollBy(0, tocNav.offsetHeight);
      }
      if (toggle.matches(':hover')) {
        /* Unfocus button when not using keyboard navigation,
           because I don’t know where else to send the focus. */
        toggle.blur();
      }
    }
  }

  function createSidebarToggle() {
    /* Create the sidebar toggle in JS; it shouldn’t exist when JS is off. */
    var toggle = document.createElement('a');
      /* This should probably be a button, but appearance isn’t standards-track.*/
    toggle.id = 'toc-toggle';
    toggle.class = 'toc-toggle';
    toggle.href = '#toc';
    toggle.innerHTML = collapseSidebarText;

    sidebarMedia.addListener(autoToggle);
    var toggler = function(e) {
      e.preventDefault();
      sidebarMedia.removeListener(autoToggle); // persist explicit off states
      toggleSidebar();
      return false;
    }
    toggle.addEventListener('click', toggler, false);


    /* Get <nav id=toc-nav>, or make it if we don’t have one. */
    var tocNav = document.getElementById('toc-nav');
    if (!tocNav) {
      tocNav = document.createElement('p');
      tocNav.id = 'toc-nav';
      /* Prepend for better keyboard navigation */
      document.body.insertBefore(tocNav, document.body.firstChild);
    }
    /* While we’re at it, make sure we have a Jump to Toc link. */
    var tocJump = document.getElementById('toc-jump');
    if (!tocJump) {
      tocJump = document.createElement('a');
      tocJump.id = 'toc-jump';
      tocJump.href = '#toc';
      tocJump.innerHTML = tocJumpText;
      tocNav.appendChild(tocJump);
    }

    tocNav.appendChild(toggle);
  }

  var toc = document.getElementById('toc');
  if (toc) {
    createSidebarToggle();
    toggleSidebar(sidebarMedia.matches);

    /* If the sidebar has been manually opened and is currently overlaying the text
       (window too small for the MQ to add the margin to body),
       then auto-close the sidebar once you click on something in there. */
    toc.addEventListener('click', function(e) {
      if(e.target.tagName.toLowerCase() == "a" && document.body.classList.contains('toc-sidebar') && !sidebarMedia.matches) {
        toggleSidebar(false);
      }
    }, false);
  }
  else {
    console.warn("Can’t find Table of Contents. Please use <nav id='toc'> around the ToC.");
  }

  /* Wrap tables in case they overflow */
  var tables = document.querySelectorAll(':not(.overlarge) > table.data, :not(.overlarge) > table.index');
  var numTables = tables.length;
  for (var i = 0; i < numTables; i++) {
    var table = tables[i];
    var wrapper = document.createElement('div');
    wrapper.className = 'overlarge';
    table.parentNode.insertBefore(wrapper, table);
    wrapper.appendChild(table);
  }

})();
</script>
  <h2 class="no-num no-ref heading settled" id="references"><span class="content">References</span><a class="self-link" href="#references"></a></h2>
  <h3 class="no-num no-ref heading settled" id="informative"><span class="content">Informative References</span><a class="self-link" href="#informative"></a></h3>
  <dl>
   <dt id="biblio-ecmascript">[ECMAScript]
   <dd><a href="https://tc39.github.io/ecma262/">ECMAScript Language Specification</a>. URL: <a href="https://tc39.github.io/ecma262/">https://tc39.github.io/ecma262/</a>
   <dt id="biblio-html5">[HTML5]
   <dd>Ian Hickson; et al. <a href="https://www.w3.org/TR/html5/">HTML5</a>. 27 March 2018. REC. URL: <a href="https://www.w3.org/TR/html5/">https://www.w3.org/TR/html5/</a>
   <dt id="biblio-p0267r7">[P0267R7]
   <dd>Michael B. McLaughlin, Herb Sutter, Jason Zink, Guy Davidson. <a href="https://wg21.link/p0267r7">A Proposal to Add 2D Graphics Rendering and Display to C++</a>. 10 February 2018. URL: <a href="https://wg21.link/p0267r7">https://wg21.link/p0267r7</a>
   <dt id="biblio-p0939r0">[P0939R0]
   <dd>B. Dawes, H. Hinnant, B. Stroustrup, D. Vandevoorde, M. Wong. <a href="https://wg21.link/p0939r0">Direction for ISO C++</a>. 10 February 2018. URL: <a href="https://wg21.link/p0939r0">https://wg21.link/p0939r0</a>
   <dt id="biblio-p1062r0">[P1062R0]
   <dd>Bryce Adelstein Lelbach, Olivier Giroux, Zach Laine, Corentin Jabot, Vittorio Romeo. <a href="https://wg21.link/p1062r0">Diet Graphics</a>. 7 May 2018. URL: <a href="https://wg21.link/p1062r0">https://wg21.link/p1062r0</a>
   <dt id="biblio-png">[PNG]
   <dd>Tom Lane. <a href="https://www.w3.org/TR/PNG/">Portable Network Graphics (PNG) Specification (Second Edition)</a>. 10 November 2003. REC. URL: <a href="https://www.w3.org/TR/PNG/">https://www.w3.org/TR/PNG/</a>
   <dt id="biblio-rfc3986">[RFC3986]
   <dd>T. Berners-Lee; R. Fielding; L. Masinter. <a href="https://tools.ietf.org/html/rfc3986">Uniform Resource Identifier (URI): Generic Syntax</a>. January 2005. Internet Standard. URL: <a href="https://tools.ietf.org/html/rfc3986">https://tools.ietf.org/html/rfc3986</a>
   <dt id="biblio-rfc6455">[RFC6455]
   <dd>I. Fette; A. Melnikov. <a href="https://tools.ietf.org/html/rfc6455">The WebSocket Protocol</a>. December 2011. Proposed Standard. URL: <a href="https://tools.ietf.org/html/rfc6455">https://tools.ietf.org/html/rfc6455</a>
   <dt id="biblio-svg11">[SVG11]
   <dd>Erik Dahlström; et al. <a href="https://www.w3.org/TR/SVG11/">Scalable Vector Graphics (SVG) 1.1 (Second Edition)</a>. 16 August 2011. REC. URL: <a href="https://www.w3.org/TR/SVG11/">https://www.w3.org/TR/SVG11/</a>
   <dt id="biblio-wai-aria">[WAI-ARIA]
   <dd>James Craig; Michael Cooper; et al. <a href="https://www.w3.org/TR/wai-aria/">Accessible Rich Internet Applications (WAI-ARIA) 1.0</a>. 20 March 2014. REC. URL: <a href="https://www.w3.org/TR/wai-aria/">https://www.w3.org/TR/wai-aria/</a>
   <dt id="biblio-webgl">[WebGL]
   <dd>Dean Jackson; Jeff Gilbert. <a href="https://www.khronos.org/registry/webgl/specs/latest/2.0/">WebGL 2.0 Specification</a>. 12 August 2017. URL: <a href="https://www.khronos.org/registry/webgl/specs/latest/2.0/">https://www.khronos.org/registry/webgl/specs/latest/2.0/</a>
   <dt id="biblio-webrtc">[WEBRTC]
   <dd>Adam Bergkvist; et al. <a href="https://www.w3.org/TR/webrtc/">WebRTC 1.0: Real-time Communication Between Browsers</a>. 27 September 2018. CR. URL: <a href="https://www.w3.org/TR/webrtc/">https://www.w3.org/TR/webrtc/</a>
   <dt id="biblio-webvtt1">[WEBVTT1]
   <dd>Silvia Pfeiffer. <a href="https://www.w3.org/TR/webvtt1/">WebVTT: The Web Video Text Tracks Format</a>. 10 May 2018. CR. URL: <a href="https://www.w3.org/TR/webvtt1/">https://www.w3.org/TR/webvtt1/</a>
  </dl>