forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add API for dealing with fragment directives
This CL implements, behind a flag, the fragment directive API described in WICG/scroll-to-text-fragment#160, allowing authors to read back directives specified in the :~: portion of the URL fragment, as well as create text-directives URLs using a Range or Selection. Because the feature was previously specific to text directives, the parsing of the URL fragment directive is currently spread across Document, TextFragmentAnchor and TextFragmentSelector. The semantics of the new API would make it more convenient to move all this logic into FragmentDirective itself but this is a sizeable change so we do this in a separate CL: https://crrev.com/c/3216206. Bug: 1214791 Change-Id: I189363a5fe9843ac1e55c7078609d61aa33bc26d Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3209166 Commit-Queue: David Bokan <[email protected]> Reviewed-by: Robert Flack <[email protected]> Cr-Commit-Position: refs/heads/main@{#933676}
- Loading branch information
Showing
31 changed files
with
1,448 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// Copyright 2021 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "third_party/blink/renderer/core/frame/directive.h" | ||
|
||
namespace blink { | ||
|
||
Directive::Directive(Type type) : type_(type) {} | ||
Directive::~Directive() = default; | ||
|
||
Directive::Type Directive::GetType() const { | ||
return type_; | ||
} | ||
|
||
String Directive::type() const { | ||
DEFINE_STATIC_LOCAL(const String, text, ("text")); | ||
|
||
switch (type_) { | ||
case kText: | ||
return text; | ||
} | ||
|
||
NOTREACHED(); | ||
return String(); | ||
} | ||
|
||
String Directive::toString() const { | ||
return ToStringImpl(); | ||
} | ||
|
||
void Directive::Trace(Visitor* visitor) const { | ||
ScriptWrappable::Trace(visitor); | ||
} | ||
|
||
} // namespace blink |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// Copyright 2021 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_DIRECTIVE_H_ | ||
#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_DIRECTIVE_H_ | ||
|
||
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" | ||
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" | ||
|
||
namespace blink { | ||
|
||
// Provides the JavaScript-exposed Directive base class used by | ||
// window.fragmentDirective.items. This is the base interface for all fragment | ||
// directive types. | ||
// See: https://github.com/WICG/scroll-to-text-fragment/issues/160 | ||
// TODO(bokan): Update link once we have better public documentation. | ||
class Directive : public ScriptWrappable { | ||
DEFINE_WRAPPERTYPEINFO(); | ||
|
||
public: | ||
enum Type { kText }; | ||
|
||
explicit Directive(Type type); | ||
~Directive() override; | ||
|
||
Type GetType() const; | ||
void Trace(Visitor*) const override; | ||
|
||
// Web-exposed Directive interface. | ||
String type() const; | ||
String toString() const; | ||
|
||
protected: | ||
// Override in subclasses to implement the toString() web-exposed method. | ||
virtual String ToStringImpl() const = 0; | ||
|
||
private: | ||
Type type_; | ||
}; | ||
|
||
} // namespace blink | ||
|
||
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_DIRECTIVE_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// Copyright 2021 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
// https://github.com/WICG/ScrollToTextFragment | ||
[ | ||
RuntimeEnabled=TextFragmentAPI | ||
] enum DirectiveType { "text" }; | ||
|
||
[ | ||
Exposed=Window, | ||
RuntimeEnabled=TextFragmentAPI | ||
] interface Directive { | ||
readonly attribute DirectiveType type; | ||
DOMString toString(); | ||
}; |
137 changes: 137 additions & 0 deletions
137
third_party/blink/renderer/core/frame/fragment_directive.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
// Copyright 2021 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "third_party/blink/renderer/core/frame/fragment_directive.h" | ||
|
||
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" | ||
#include "third_party/blink/renderer/bindings/core/v8/v8_union_range_selection.h" | ||
#include "third_party/blink/renderer/core/dom/document.h" | ||
#include "third_party/blink/renderer/core/dom/range.h" | ||
#include "third_party/blink/renderer/core/editing/dom_selection.h" | ||
#include "third_party/blink/renderer/core/editing/ephemeral_range.h" | ||
#include "third_party/blink/renderer/core/frame/local_frame.h" | ||
#include "third_party/blink/renderer/core/frame/text_directive.h" | ||
#include "third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.h" | ||
#include "third_party/blink/renderer/platform/bindings/exception_code.h" | ||
#include "third_party/blink/renderer/platform/bindings/exception_state.h" | ||
#include "third_party/blink/renderer/platform/bindings/script_state.h" | ||
|
||
namespace blink { | ||
|
||
FragmentDirective::FragmentDirective(Document& owner_document) | ||
: owner_document_(&owner_document) {} | ||
FragmentDirective::~FragmentDirective() = default; | ||
|
||
void FragmentDirective::ClearDirectives() { | ||
directives_.clear(); | ||
} | ||
|
||
void FragmentDirective::AddDirective(Directive* directive) { | ||
directives_.push_back(directive); | ||
} | ||
|
||
void FragmentDirective::Trace(Visitor* visitor) const { | ||
ScriptWrappable::Trace(visitor); | ||
visitor->Trace(directives_); | ||
visitor->Trace(owner_document_); | ||
} | ||
|
||
const HeapVector<Member<Directive>>& FragmentDirective::items() const { | ||
return directives_; | ||
} | ||
|
||
namespace { | ||
void RejectWithCode(ScriptPromiseResolver* resolver, | ||
DOMExceptionCode code, | ||
const String& message) { | ||
ScriptState::Scope scope(resolver->GetScriptState()); | ||
ExceptionState exception_state(resolver->GetScriptState()->GetIsolate(), | ||
ExceptionState::kExecutionContext, | ||
"FragmentDirective", | ||
"createSelectorDirective"); | ||
exception_state.ThrowDOMException(code, message); | ||
resolver->Reject(exception_state); | ||
} | ||
} // namespace | ||
|
||
ScriptPromise FragmentDirective::createSelectorDirective( | ||
ScriptState* state, | ||
const V8UnionRangeOrSelection* arg) { | ||
if (ExecutionContext::From(state)->IsContextDestroyed()) | ||
return ScriptPromise(); | ||
|
||
ScriptPromiseResolver* resolver = | ||
MakeGarbageCollected<ScriptPromiseResolver>(state); | ||
|
||
// Access the promise first to ensure it is created so that the proper state | ||
// can be changed when it is resolved or rejected. | ||
ScriptPromise promise = resolver->Promise(); | ||
|
||
Range* range = nullptr; | ||
|
||
if (arg->GetContentType() == | ||
V8UnionRangeOrSelection::ContentType::kSelection) { | ||
DOMSelection* selection = arg->GetAsSelection(); | ||
if (selection->rangeCount() == 0) { | ||
RejectWithCode(resolver, DOMExceptionCode::kNotSupportedError, | ||
"Selection must contain a range"); | ||
return promise; | ||
} | ||
|
||
range = selection->getRangeAt(0, ASSERT_NO_EXCEPTION); | ||
} else { | ||
DCHECK_EQ(arg->GetContentType(), | ||
V8UnionRangeOrSelection::ContentType::kRange); | ||
range = arg->GetAsRange(); | ||
} | ||
|
||
if (!range || range->collapsed()) { | ||
RejectWithCode(resolver, DOMExceptionCode::kNotSupportedError, | ||
"RangeOrSelector must be non-null and non-collapsed"); | ||
return promise; | ||
} | ||
|
||
if (range->OwnerDocument() != owner_document_) { | ||
RejectWithCode(resolver, DOMExceptionCode::kWrongDocumentError, | ||
"RangeOrSelector must be from this document"); | ||
return promise; | ||
} | ||
|
||
LocalFrame* frame = range->OwnerDocument().GetFrame(); | ||
if (!frame) { | ||
RejectWithCode(resolver, DOMExceptionCode::kInvalidStateError, | ||
"Document must be attached to frame"); | ||
return promise; | ||
} | ||
|
||
EphemeralRangeInFlatTree ephemeral_range(range); | ||
RangeInFlatTree* range_in_flat_tree = MakeGarbageCollected<RangeInFlatTree>( | ||
ephemeral_range.StartPosition(), ephemeral_range.EndPosition()); | ||
|
||
auto* generator = MakeGarbageCollected<TextFragmentSelectorGenerator>(frame); | ||
generator->Generate( | ||
*range_in_flat_tree, | ||
WTF::Bind( | ||
[](ScriptPromiseResolver* resolver, | ||
TextFragmentSelectorGenerator* generator, | ||
const RangeInFlatTree* range, | ||
const TextFragmentSelector& selector) { | ||
if (selector.Type() == | ||
TextFragmentSelector::SelectorType::kInvalid) { | ||
RejectWithCode(resolver, DOMExceptionCode::kOperationError, | ||
"Failed to generate selector for the given range"); | ||
return; | ||
} | ||
TextDirective* dom_text_directive = | ||
MakeGarbageCollected<TextDirective>(selector); | ||
dom_text_directive->DidFinishMatching(range); | ||
resolver->Resolve(dom_text_directive); | ||
}, | ||
WrapPersistent(resolver), WrapPersistent(generator), | ||
WrapPersistent(range_in_flat_tree))); | ||
|
||
return promise; | ||
} | ||
|
||
} // namespace blink |
Oops, something went wrong.