diff --git a/index.bs b/index.bs index b2e321a..5ce7a41 100644 --- a/index.bs +++ b/index.bs @@ -84,6 +84,26 @@ spec: media-source; urlPrefix: http://w3c.github.io/media-source/ text: MediaSource; url: #mediasource + + # Introduction # {#intro} *This section is informative.* @@ -209,16 +229,6 @@ this is the same time that is conceptually "0" in ECMA-262 [[ECMA-2 # The Blob Interface and Binary Data # {#blob-section} -A {{Blob}} object refers to a byte sequence, -and has a {{Blob/size}} attribute which is the total number of bytes in the byte sequence, -and a {{Blob/type}} attribute, -which is an ASCII-encoded string in lower case representing the media type of the byte sequence. - -Each {{Blob}} must have an internal snapshot state, -which must be initially set to the state of the underlying storage, -if any such underlying storage exists. -Further normative definition of snapshot state can be found for {{File}}s. - [Exposed=(Window,Worker), Serializable] interface Blob { @@ -249,18 +259,43 @@ dictionary BlobPropertyBag { typedef (BufferSource or Blob or USVString) BlobPart; -{{Blob}} objects are [=serializable objects=]. Their [=serialization steps=], -given |value| and |serialized|, are: +A {{Blob}} has an associated \[[type]] internal slot, +an ASCII-encoded string in lower case representing the media type of the byte sequence. -1. Set |serialized|.\[[SnapshotState]] to |value|'s [=snapshot state=]. +A {{Blob}} has an associated \[[data]] internal slot, +a [=blob data description=]. -2. Set |serialized|.\[[ByteSequence]] to |value|'s underlying byte sequence. +
+{{Blob}} objects are [=serializable objects=]. Their [=serialization steps=] +(the blob serialization steps), +given |value|, |serialized| and |forStorage|, are: -Their [=deserialization step=], given |serialized| and |value|, are: +1. If |forStorage| is true: + 1. Let |bytes| be the result of [=read all bytes|reading all bytes=] from |value|. + 1. Set |serialized|.\[[BlobData]] to the result of [=creating blob data from bytes=] given |bytes|. + +1. Otherwise: + 1. Set |serialized|.\[[BlobData]] to |value|.[=[[data]]=]. + +1. Set |serialized|.\[[Type]] to |value|.[=[[type]]=]. + +
+ +
+Their [=deserialization step=] (the blob deserialization steps), +given |serialized| and |value|, are: -1. Set |value|'s [=snapshot state=] to |serialized|.\[[SnapshotState]]. +1. Set |value|.[=[[data]]=] to |serialized|.\[[BlobData]]. -2. Set |value|'s underlying byte sequence to |serialized|.\[[ByteSequence]]. +1. Set |value|.[=[[type]]=] to |serialized|.\[[Type]]. + +
+ +Issue(w3c/webappsec-clear-site-data#49): The actual storage API |serialized| was persisted in will need a way of +modifying the read algorithms for deserialized blobs. I.e. a Blob that was +deserialized from IndexedDB should start throwing in its read steps after +clear-site-data clears all IndexedDB data. Somehow let StructuredDeserialize +pass along a hook from the storage API to here?
A {{Blob}} |blob| has an associated get stream algorithm, @@ -269,88 +304,146 @@ which runs these steps: 1. Let |stream| be the result of [=construct a ReadableStream object|constructing=] a {{ReadableStream}} object. 1. Run the following steps [=in parallel=]: - 1. While not all bytes of |blob| have been read: - 1. Let |bytes| be the [=byte sequence=] that results from reading a [=chunk=] from |blob|. - 1. If a [=file read error=] occured while reading |bytes|, [$ReadableStream/error$] - |stream| with a [=failure reason=] and abort these steps. + 1. Let |blob data| be |blob|.[=[[data]]=]. + 1. Let |read state| be the result of calling |blob data|'s [=read initialization algorithm=] + given |blob data|'s [=snapshot state=] and 0. + If that threw an exception, [$ReadableStream/error$] |stream| with that exception + and abort these steps. + 1. While true: + 1. Let |read result| be the result of calling |blob data|'s [=read algorithm=] given |read state|. + 1. If that threw an exception (a [=file read error=]), + [$ReadableStream/error$] |stream| with that [=failure reason=] and abort these steps. + 1. If |read result| is [=end of blob=], [=break=]. 1. [=ReadableStream/Enqueue=] a `Uint8Array` object wrapping an `ArrayBuffer` - containing |bytes| into |stream|. - If that threw an exception, [$ReadableStream/error$] |stream| with that exception - and abort these steps. + containing |read result| into |stream|. + If that threw an exception, [$ReadableStream/error$] |stream| with that exception + and abort these steps. - Issue: We need to specify more concretely what reading from a Blob actually does, + Issue(144): We need to specify more concretely what reading from a Blob actually does, what possible errors can happen, perhaps something about chunk sizes, etc. 1. Return |stream|.
-## Constructors ## {#constructorBlob} +## Concepts ## {#blobConcepts} -
-The {{Blob()}} constructor can be invoked with zero or more parameters. -When the {{Blob()}} constructor is invoked, -user agents must run the following steps: +The data represented by a {{Blob}} is described by a blob data description, +consisting of some representation of the data, combined with a set of algorithms to +return the actual data as a series of [=byte sequences=]. -1. If invoked with zero parameters, - return a new {{Blob}} object consisting of 0 bytes, - with {{Blob/size}} set to 0, - and with {{Blob/type}} set to the empty string. +A [=blob data description=] has an associated size, +a number specifying the total number of bytes in the byte sequence represented by the blob. -1. Let |bytes| be the result of [=processing blob parts=] given {{blobParts}} and {{Blob/Blob(blobParts, options)/options}}. +A [=blob data description=] has an associated snapshot state. +This is a [=map=] that represents the data stored in the blob. -1. If the {{BlobPropertyBag/type}} member of the {{Blob/Blob(blobParts, options)/options}} argument is not the empty string, - run the following sub-steps: +A [=blob data description=] has an associated read initialization algorithm. +This algorithm takes two arguments: the snapshot state, and a byte offset. +It returns a [=struct=] which will be used as input for the [=read algorithm=]. + +A [=blob data description=] has an associated read algorithm. +This algorithm takes one argument (the [=struct=] returned by the [=read initialization algorithm=]). +It returns either a [=byte sequence=] or the special end of blob value. + +
+To read all bytes from a {{Blob}} |blob|, run these steps: - 1. Let |t| be the {{BlobPropertyBag/type}} dictionary member. - If |t| contains any characters outside the range U+0020 to U+007E, - then set |t| to the empty string and return from these substeps. - 1. Convert every character in |t| to [=ASCII lowercase=]. +1. Let |bytes| be an empty [=byte sequence=]. +1. Let |blob data| be |blob|.[=[[data]]=]. +1. Let |read state| be the result of calling |blob data|'s [=read initialization algorithm=] + given |blob data|'s [=snapshot state=] and 0. +1. While true: + 1. Let |read result| be the result of calling |blob data|'s [=read algorithm=] given |read state|. + 1. If |read result| is [=end of blob=], [=break=]. + 1. Append |read result| to |bytes|. +1. Return |bytes|. + +
+ +Conceptually a {{Blob}} represents a snapshot of some amount of data, and +is frozen in time at the time a {{Blob}} instance is created. +As such for any specific instance of a {{Blob}}, every invocation of [=read all bytes=] +should either return the exact same [=byte sequence=], or throw an exception. +Additionally the returned [=byte sequence=]'s [=byte sequence/length=] should be equal to +the blob [=[[data]]=]'s [=blob data/size=]. + +Note: This is a non-trivial requirement to implement for user agents, especially +when a blob is backed by a file on disk (i.e. was created by the +[=create a file backed File object=] algorithm). +User agents can use modification time stamps and other mechanisms to maintain +this requirement, but this is left as an implementation detail. + +### Byte Sequence backed blobs ### {#byte-sequence-backed-blobs} + +The [=snapshot state=] for a byte sequence backed blob contains a +"data" member, a [=byte sequence=]. + +
+To create blob data from bytes +given |bytes| (a [=byte sequence=]), run the following steps: + +1. Let |blob data| be a new [=blob data description=]. +1. Set |blob data|.[=snapshot state=]["data"] to |bytes|. + +1. Set |blob data|.[=read initialization algorithm=] to the [=bytes blob read initialization steps=]. +1. Set |blob data|.[=read algorithm=] to the [=bytes blob read steps=]. -1. Return a {{Blob}} object referring to |bytes| as its associated byte sequence, - with its {{Blob/size}} set to the length of |bytes|, - and its {{Blob/type}} set to the value of |t| from the substeps above. +1. Return |blob data|.
-### Constructor Parameters ### {#constructorParams} +A bytes blob read state is a [=struct=] conssting of +bytes (a [=byte sequence=]). -The {{Blob()}} constructor can be invoked with the parameters below: +
+The bytes blob read initialization steps, +given a |snapshot state| and |offset| are: -
-
A blobParts sequence -
which takes any number of the following types of elements, and in any order: - * {{BufferSource}} elements. - * {{Blob}} elements. - * {{USVString}} elements. - -
An *optional* {{BlobPropertyBag}} -
which takes these optional members: - * type, - the ASCII-encoded string in lower case representing the media type of the {{Blob}}. - Normative conditions for this member are provided in the [[#constructorBlob]]. - * endings, - an enum which can take the values {{"transparent"}} or {{"native"}}. - By default this is set to {{"transparent"}}. If set to {{"native"}}, - [=convert line endings to native|line endings will be converted to native=] - in any {{USVString}} elements in {{blobParts}}. -
+1. Let |read state| be a new [=bytes blob read state=]. +1. If |offset| is larger than |snapshot state|["data"]'s [=byte sequence/length=], + set |read state|.[=bytes blob read state/bytes=] to an empty [=byte sequence=]. +1. Otherwise, set |read state|.[=bytes blob read state/bytes=] to + a copy of |snapshot state|["data"] with the first |offset| bytes removed. +1. Return |read state|. + +
+ +
+The bytes blob read steps, +given |read state| (a [=bytes blob read state=]) are: + +1. Let |result| be |read state|.[=bytes blob read state/bytes=]. +1. Set |read state|.[=bytes blob read state/bytes=] to an empty [=byte sequence=]. +1. If |result| is empty, return [=end of blob=]. +1. Return |result|. + +
+ +### Multipart blobs ### {#multipart-blobs} + +Blobs created by the {{Blob}} and {{File}} constructors are made up of multiple parts, +where each part could be a blob itself. + +The [=snapshot state=] for a multipart blob contains a +"parts" member, +a [=list=] of [=blob data descriptions=].
-To process blob parts given a sequence of {{BlobPart}}'s |parts| -and {{BlobPropertyBag}} |options|, +To process blob parts +given a sequence of {{BlobPart}}'s |blobParts| and {{BlobPropertyBag}} |options|, run the following steps: -1. Let |bytes| be an empty sequence of bytes. +1. Let |size| be 0. +1. Let |parts| be an empty [=list=]. -1. For each |element| in |parts|: +1. Let |bytes| be an empty [=byte sequence=]. +1. For each |element| in |blobParts|: 1. If |element| is a {{USVString}}, run the following substeps: 1. Let |s| be |element|. - 1. If the {{BlobPropertyBag/endings}} member of |options| is {{"native"}}, set |s| to the result of [=converting line endings to native=] of |element|. - 1. Append the result of [=UTF-8 encoding=] |s| to |bytes|. Note: The algorithm from WebIDL [[WebIDL]] replaces unmatched surrogates in an invalid utf-16 string @@ -361,16 +454,179 @@ run the following steps: 1. If |element| is a {{BufferSource}}, get a copy of the bytes held by the buffer source, and append those bytes to |bytes|. - 1. If |element| is a {{Blob}}, - append the bytes it represents to |bytes|. + 1. If |element| is a {{Blob}}: + 1. If |bytes| is not empty: + 1. Let |part| be the result of [=creating blob data from bytes=] given |bytes|. + 1. [=list/Append=] |part| to |parts|. + 1. Set |size| to |size| + |part|.[=blob data/size=]. + 1. Set |bytes| to an empty [=byte sequence=]. + + 1. Let |part| be |element|.[=[[data]]=]. + 1. [=list/Append=] |part| to |parts|. + 1. Set |size| to |size| + |part|.[=blob data/size=]. Note: The {{Blob/type}} of the {{Blob}} array element is ignored and will not affect {{Blob/type}} of returned {{Blob}} object. -1. Return |bytes|. +1. If |bytes| is not empty: + 1. Let |part| be the result of [=creating blob data from bytes=] given |bytes|. + 1. [=list/Append=] |part| to |parts|. + 1. Set |size| to |size| + |part|.[=blob data/size=]. + +1. Let |result| be a [=blob data description=]. +1. Set |result|.[=blob data/size=] to |size|. +1. Set |result|.[=snapshot state=]["parts"] to |parts|. +1. Set |result|.[=read initialization algorithm=] to the [=multipart blob read initialization steps=]. +1. Set |result|.[=read algorithm=] to the [=multipart blob read steps=]. + +1. Return |result|. + +
+ +A multipart blob read state is a [=struct=] consisting of: + +
+: parts +:: A [=queue=] of [=blob data descriptions=], representing the not yet read parts of the blob. +: offset +:: A number, representing the byte offset in the remaining blob parts + from which to start returning data. +: nested blob data +:: `undefined` or a [=blob data description=]. This is `undefined` unless otherwise specified. +: nested read state +:: `undefined` or a [=struct=], representing the read state for a nested read operation. + This is `undefined` unless otherwise specified. + +
+ +
+The multipart blob read initialization steps, given a |snapshot state| and |offset| are: + +1. Let |read state| be a new [=multipart blob read state=]. +1. Set |read state|.[=multipart blob read state/parts=] to + a [=queue/clone=] of |snapshot state|["parts"]. +1. Set |read state|.[=multipart blob read state/offset=] to |offset|. +1. Return |read state|. + +
+ +
+The multipart blob read steps, given |read state| (a [=multipart blob read state=]) are: + +1. Let |result| be [=end of blob=]. +1. While |result| is [=end of blob=]: + + 1. If |read state|.[=multipart blob read state/nested read state=] is not `undefined`: + 1. [=Assert=]: |read state|.[=multipart blob read state/offset=] is 0. + 1. Set |result| to the result of calling + |read state|.[=multipart blob read state/nested blob data=]'s [=read algorithm=] + given |read state|.[=multipart blob read state/nested read state=]. + 1. If |result| is [=end of blob=]: + 1. Set |read state|.[=multipart blob read state/nested read state=] to `undefined`. + 1. Set |read state|.[=multipart blob read state/nested blob data=] to `undefined`. + + 1. Otherwise: + 1. If |read state|.[=multipart blob read state/parts=] is empty: + 1. Return [=end of blob=]. + + 1. Let |current part| be the result of [=dequeueing=] from |read state|.[=multipart blob read state/parts=]. + 1. If |read state|.[=multipart blob read state/offset=] >= |current part|.[=blob data/size=]: + 1. Set |read state|.[=multipart blob read state/offset=] to + |read state|.[=multipart blob read state/offset=] - |current part|.[=blob data/size=]. + 1. [=Continue=]. + + 1. Set |read state|.[=multipart blob read state/nested blob data=] to |current part|. + 1. Set |read state|.[=multipart blob read state/nested read state=] to the result of calling + |current part|'s [=read initialization algorithm=] + given |current part|'s [=snapshot state=] + and |read state|.[=multipart blob read state/offset=]. + 1. Set |read state|.[=multipart blob read state/offset=] to 0. + +1. Return |result|. + +
+ +### Sliced blobs ### {#sliced-blobs} + +Blobs created by the {{Blob/slice()}} method are also known as sliced blobs. + +The [=snapshot state=] for a sliced blob contains +a "offset" member (a number), +a "span" member (a number), +and a "source" member (a [=blob data description=]). + +A sliced blob read state is a [=struct=] consisting of: + +
+: source +:: A [=blob data description=], representing the blob that was sliced. +: bytes remaining +:: A number, representing the remaining number of bytes to be returned. +: nested read state +:: A [=struct=], representing the read state of the nested read operation. + +
+ +
+The sliced blob read initialization steps, given a |snapshot state| and |offset| are: + +1. Let |read state| be a new [=sliced blob read state=]. +1. Set |read state|.[=sliced blob read state/source=] to + |snapshot state|["source"]. +1. Set |read state|.[=sliced blob read state/bytes remaining=] to + |snapshot state|["span"] - |offset|. +1. Let |read offset| be |snapshot state|["offset"] + |offset|. +1. Set |read state|.[=sliced blob read state/nested read state=] to the result of calling + |read state|.[=sliced blob read state/source=]'s [=read initialization algorithm=] + given |read state|.[=sliced blob read state/source=]'s [=snapshot state=] + and |read offset|. +1. Return |read state|. + +
+ +
+The sliced blob read steps, given |read state| (a [=sliced blob read state=]) are: + +1. If |read state|.[=sliced blob read state/bytes remaining=] <= 0: + 1. Return [=end of blob=]. + +1. Let |result| be the result of calling + |read state|.[=sliced blob read state/source=]'s [=read algorithm=] + given |read state|.[=sliced blob read state/nested read state=]. +1. If |result| is not [=end of blob=]: + 1. If |result|'s [=byte sequence/length=] is larger than |read state|.[=sliced blob read state/bytes remaining=]: + 1. Truncate |result| to be |read state|.[=sliced blob read state/bytes remaining=] bytes long. + + 1. Set |read state|.[=sliced blob read state/bytes remaining=] to + |read state|.[=sliced blob read state/bytes remaining=] - |result|'s [=byte sequence/length=]. + +1. Return |result|.
+## Constructors ## {#constructorBlob} + + +
+The new Blob(|blobParts|, |options|) constructor steps are: + +1. Let |blob data| be the result of [=processing blob parts=] given |blobParts| and |options|. +1. Set [=this=].[=[[data]]=] to |blob data|. + +1. Let |type| be an empty string. +1. If the {{BlobPropertyBag/type}} member of the {{Blob/Blob(blobParts, options)/options}} argument is not the empty string, + run the following sub-steps: + + 1. Let |type| be the {{BlobPropertyBag/type}} dictionary member. + If |type| contains any characters outside the range U+0020 to U+007E, + then set |type| to the empty string and return from these substeps. + 1. Convert every character in |type| to [=ASCII lowercase=]. + +1. Set [=this=].[=[[type]]=] to |type|. + +
+ +
To convert line endings to native in a [=string=] |s|, @@ -449,93 +705,82 @@ run the following steps: ## Attributes ## {#attributes-blob} -
-
size -
Returns the size of the byte sequence in number of bytes. - On getting, conforming user agents must return the total number of bytes that can be read by a {{FileReader}} or {{FileReaderSync}} object, - or 0 if the {{Blob}} has no bytes to be read. - -
type -
The ASCII-encoded string in lower case representing the media type of the {{Blob}}. - On getting, user agents must return the type of a {{Blob}} - as an ASCII-encoded string in lower case, - such that when it is converted to a byte sequence, - it is a parsable MIME type, - or the empty string – 0 bytes – if the type cannot be determined. +
+: |blob| . {{Blob/size}} +:: Returns the size of the [=byte sequence=] represented by |blob| in number of bytes. - The {{Blob/type}} attribute can be set by the web application itself through constructor invocation - and through the {{Blob/slice()}} call; - in these cases, further normative conditions for this attribute are in [[#constructorBlob]], - [[#file-constructor]], - and [[#slice-method-algo]] respectively. - User agents can also determine the {{Blob/type}} of a {{Blob}}, - especially if the byte sequence is from an on-disk file; - in this case, further normative conditions are in the file type guidelines. - - Note: The type t of a {{Blob}} is considered a parsable MIME type, - if performing the parse a MIME type algorithm to a byte sequence converted from - the ASCII-encoded string representing the Blob object's type does not return failure. - - Note: Use of the {{Blob/type}} attribute informs the [=package data=] algorithm - and determines the `Content-Type` header when [=/fetching=] [=blob URLs=]. -
+
+ +The size getter steps are to return [=this=].[=[[data]]=].[=blob data/size=]. + +
+: |blob| . {{Blob/type}} +:: The ASCII-encoded string in lower case representing the media type of the {{Blob}}, + or an empty string if the type cannot be determined. + + The {{Blob/type}} attribute can be set by the web application itself through constructor invocation + and through the {{Blob/slice()}} call; + + Note: The type of a {{Blob}} is considered a parsable MIME type, + if performing the parse a MIME type algorithm to a byte sequence converted from + the ASCII-encoded string representing the Blob object's type does not return failure. + + Note: Use of the {{Blob/type}} attribute informs the [=package data=] algorithm + and determines the `Content-Type` header when [=/fetching=] [=blob URLs=]. + +
+ +The type getter steps are to return [=this=].[=[[type]]=]. ## Methods and Parameters ## {#methodsandparams-blob} ### The {{Blob/slice()}} method ### {#slice-method-algo} -The slice() method -returns a new {{Blob}} object with bytes ranging from -the optional {{start}} parameter -up to but not including the optional {{end}} parameter, -and with a {{Blob/type}} attribute that is the value of the optional {{contentType!!argument}} parameter. -It must act as follows: - -1. Let |O| be the {{Blob}} context object on which the {{slice()}} method is being called. -2. The optional start parameter - is a value for the start point of a {{slice()}} call, - and must be treated as a byte-order position, - with the zeroth position representing the first byte. - User agents must process {{Blob/slice()}} with {{start}} normalized according to the following: - -
    -
  1. If the optional {{start}} parameter is not used as a parameter when making this call, let |relativeStart| be 0. -
  2. If {{start}} is negative, let |relativeStart| be max(({{Blob/size}} + {{start}}), 0). -
  3. Else, let |relativeStart| be min(start, size). -
- -3. The optional end parameter - is a value for the end point of a {{slice()}} call. - User agents must process {{Blob/slice()}} with {{end}} normalized according to the following: - -
    -
  1. If the optional {{end}} parameter is not used as a parameter when making this call, let |relativeEnd| be {{Blob/size}}. -
  2. If {{end}} is negative, let |relativeEnd| be max((size + end), 0). -
  3. Else, let |relativeEnd| be min(end, size). -
- -4. The optional contentType parameter - is used to set the ASCII-encoded string in lower case representing the media type of the Blob. - User agents must process the {{Blob/slice()}} with {{contentType}} normalized according to the following: - -
    -
  1. If the {{contentType}} parameter is not provided, let |relativeContentType| be set to the empty string. -
  2. Else let |relativeContentType| be set to {{contentType}} and run the substeps below: - 1. If |relativeContentType| contains any characters outside the range of U+0020 to U+007E, - then set |relativeContentType| to the empty string and return from these substeps. - 2. Convert every character in |relativeContentType| to [=ASCII lowercase=]. -
- -5. Let |span| be max((relativeEnd - relativeStart), 0). - -6. Return a new {{Blob}} object |S| with the following characteristics: - -
    -
  1. |S| refers to |span| consecutive bytes from |O|, - beginning with the byte at byte-order position |relativeStart|. -
  2. |S|.{{Blob/size}} = |span|. -
  3. |S|.{{Blob/type}} = |relativeContentType|. -
+
+: |slice| = |blob| . {{Blob/slice()|slice}}( |start|, |end|, |contentType| ) +:: |slice| is a new {{Blob}} object, sharing storage with |blob|, with bytes ranging from + the optional |start| parameter + up to but not including the optional |end| parameter, + and with a {{Blob/type}} attribute that is the value of the optional |contentType| parameter. + + Negative values for |start| and |end| are interpreted as relative to the end of the |blob|. + +
+ +
+The slice(|start|, |end|, |contentType|) method steps are: + +1. Let |relativeStart| be 0. +1. If |start| is not `undefined`: + 1. If |start| < 0, set |relativeStart| to max([=this=].[=[[data]]=].[=blob data/size=] + |start|, 0). + 1. Otherwise, set |relativeStart| to min(|start|, [=this=].[=[[data]]=].[=blob data/size=]). + +1. Let |relativeEnd| be [=this=].[=[[data]]=].[=blob data/size=]. +1. If |end| is not `undefined`: + 1. If |end| < 0, set |relativeEnd| to max([=this=].[=[[data]]=].[=blob data/size=] + |end|, 0). + 1. Otherwise, set |relativeEnd| to min(|end|, [=this=].[=[[data]]=].[=blob data/size=]). + +1. Let |span| be max((relativeEnd - relativeStart), 0). + +1. Let |relativeContentType| be an empty string. +1. If |contentType| is not `undefined`: + 1. If |contentType| does not contain any characters outside the range of U+0x0020 to U+0x007E: + 1. Set |relativeContentType| to [=ASCII lowercase=] of |contentType|. + +1. Let |snapshot state| be a new [=map=]. +1. Set |snapshot state|["offset"] to |relativeStart|. +1. Set |snapshot state|["span"] to |span|. +1. Set |snapshot state|["source"] to [=this=].[=[[data]]=]. + +1. Let |result| be a new {{Blob}} object. +1. Set |result|.[=[[type]]=] to |relativeContentType|. +1. Set |result|.[=[[data]]=].[=blob data/size=] to |span|. +1. Set |result|.[=[[data]]=].[=snapshot state=] to |snapshot state|. +1. Set |result|.[=[[data]]=].[=read initialization algorithm=] to the [=sliced blob read initialization steps=]. +1. Set |result|.[=[[data]]=].[=read algorithm=] to the [=sliced blob read steps=]. +1. Return |result|. + +
The examples below illustrate the different types of {{slice()}} calls possible. Since the @@ -578,12 +823,12 @@ the result of calling [=get stream=] on the [=context object=]. The text() method, when invoked, must run these steps: -1. Let |stream| be the result of calling [=get stream=] on the [=context object=]. -1. Let |reader| be the result of [=get a reader|getting a reader=] from |stream|. - If that threw an exception, return a new promise rejected with that exception. -1. Let |promise| be the result of [=read all bytes|reading all bytes=] from |stream| with |reader|. -1. Return the result of transforming |promise| by a fulfillment handler that returns the result of - running [=UTF-8 decode=] on its first argument. +1. Let |promise| be [=a new Promise=]. +1. Run the following steps [=in parallel=]: + 1. Let |bytes| be the result of [=read all bytes|reading all bytes=] from [=this=]. + If that threw an exception, [=/reject=] |promise| with that exception and abort. + 1. [=/Resolve=] |promise| with the result of running [=UTF-8 decode=] on |bytes|. +1. Return |promise|. Note: This is different from the behavior of {{FileReader/readAsText()}} to align better with the behavior of {{Body/text()|Fetch's text()}}. Specifically this method will always @@ -594,12 +839,13 @@ the blob's type and passed in encoding name. The arrayBuffer() method, when invoked, must run these steps: -1. Let |stream| be the result of calling [=get stream=] on the [=context object=]. -1. Let |reader| be the result of [=get a reader|getting a reader=] from |stream|. - If that threw an exception, return a new promise rejected with that exception. -1. Let |promise| be the result of [=read all bytes|reading all bytes=] from |stream| with |reader|. -1. Return the result of transforming |promise| by a fulfillment handler that returns - a new {{ArrayBuffer}} whose contents are its first argument. +1. Let |promise| be [=a new Promise=]. +1. Run the following steps [=in parallel=]: + 1. Let |bytes| be the result of [=read all bytes|reading all bytes=] from [=this=]. + If that threw an exception, [=/reject=] |promise| with that exception and abort. + 1. [=/Resolve=] |promise| with a new {{ArrayBuffer}} whose contents are |bytes|. +1. Return |promise|. +