| // Copyright 2012 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CONTENT_RENDERER_ACCESSIBILITY_RENDER_ACCESSIBILITY_IMPL_H_ |
| #define CONTENT_RENDERER_ACCESSIBILITY_RENDER_ACCESSIBILITY_IMPL_H_ |
| |
| #include <memory> |
| #include <vector> |
| |
| #include "base/memory/raw_ptr.h" |
| #include "base/memory/raw_ptr_exclusion.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/time/time.h" |
| #include "content/common/content_export.h" |
| #include "content/public/renderer/render_accessibility.h" |
| #include "content/public/renderer/render_frame.h" |
| #include "content/public/renderer/render_frame_observer.h" |
| #include "third_party/blink/public/mojom/render_accessibility.mojom.h" |
| #include "third_party/blink/public/web/web_ax_context.h" |
| #include "third_party/blink/public/web/web_ax_object.h" |
| #include "ui/accessibility/ax_event.h" |
| #include "ui/accessibility/ax_tree_update.h" |
| |
| namespace base { |
| class ElapsedTimer; |
| } // namespace base |
| |
| namespace blink { |
| class WebDocument; |
| } // namespace blink |
| |
| namespace ui { |
| |
| struct AXActionData; |
| class AXActionTarget; |
| |
| } // namespace ui |
| |
| namespace ukm { |
| class MojoUkmRecorder; |
| } |
| |
| namespace content { |
| |
| class AXAnnotatorsManager; |
| class RenderFrameImpl; |
| class RenderAccessibilityManager; |
| |
| // The browser process implements native accessibility APIs, allowing assistive |
| // technology (e.g., screen readers, magnifiers) to access and control the web |
| // contents with high-level APIs. These APIs are also used by automation tools, |
| // and Windows 8 uses them to determine when the on-screen keyboard should be |
| // shown. |
| // |
| // An instance of this class belongs to the RenderAccessibilityManager object. |
| // Accessibility is initialized based on the ui::AXMode passed from the browser |
| // process to the manager object; it lazily starts as Off or EditableTextOnly |
| // depending on the operating system, and switches to Complete if assistive |
| // technology is detected or a flag is set. |
| // |
| // A tree of accessible objects is built here and sent to the browser process; |
| // the browser process maintains this as a tree of platform-native accessible |
| // objects that can be used to respond to accessibility requests from other |
| // processes. |
| // |
| // This class implements complete accessibility support for assistive |
| // technology. It turns on Blink's accessibility code and sends a serialized |
| // representation of that tree whenever it changes. It also handles requests |
| // from the browser to perform accessibility actions on nodes in the tree (e.g., |
| // change focus, or click on a button). |
| class CONTENT_EXPORT RenderAccessibilityImpl : public RenderAccessibility, |
| public RenderFrameObserver { |
| public: |
| // A call to NotifyAccessibilityModeChange() is required after construction |
| // to start accessibility. |
| RenderAccessibilityImpl( |
| RenderAccessibilityManager* const render_accessibility_manager, |
| RenderFrameImpl* const render_frame); |
| |
| RenderAccessibilityImpl(const RenderAccessibilityImpl&) = delete; |
| RenderAccessibilityImpl& operator=(const RenderAccessibilityImpl&) = delete; |
| |
| ~RenderAccessibilityImpl() override; |
| |
| void NotifyAccessibilityModeChange(const ui::AXMode& mode); |
| ui::AXMode GetAccessibilityMode() { return accessibility_mode_; } |
| |
| // RenderAccessibility implementation. |
| bool HasActiveDocument() const override; |
| ui::AXMode GetAXMode() const override; |
| void SetPluginAXTreeActionTargetAdapter( |
| PluginAXTreeActionTargetAdapter* adapter) override; |
| #if BUILDFLAG(IS_CHROMEOS) |
| void FireLayoutComplete() override; |
| #endif // BUILDFLAG(IS_CHROMEOS) |
| |
| // RenderFrameObserver implementation. |
| void DidCreateNewDocument() override; |
| void DidCommitProvisionalLoad(ui::PageTransition transition) override; |
| |
| void HitTest(const gfx::Point& point, |
| ax::mojom::Event event_to_fire, |
| int request_id, |
| blink::mojom::RenderAccessibility::HitTestCallback callback); |
| void PerformAction(const ui::AXActionData& data); |
| void Reset(uint32_t reset_token); |
| |
| // Called when accessibility mode changes so that any obsolete accessibility |
| // bundles for the old mode can be ignored. |
| void set_reset_token(uint32_t reset_token); |
| |
| // Called when an accessibility notification occurs in Blink. |
| void HandleAXEvent(const ui::AXEvent& event); |
| // An AXObject should be serialized at the next available opportunity. |
| void MarkWebAXObjectDirty( |
| const blink::WebAXObject& obj, |
| ax::mojom::EventFrom event_from = ax::mojom::EventFrom::kNone, |
| ax::mojom::Action event_from_action = ax::mojom::Action::kNone, |
| std::vector<ui::AXEventIntent> event_intents = {}, |
| ax::mojom::Event event_type = ax::mojom::Event::kNone); |
| |
| void NotifyWebAXObjectMarkedDirty(const blink::WebAXObject& obj, |
| ax::mojom::Event event_type = ax::mojom::Event::kNone); |
| // Called when it is safe to begin a serialization. |
| // Returns true if a serialization occurs. |
| bool SendAccessibilitySerialization( |
| std::vector<ui::AXTreeUpdate> updates, |
| std::vector<ui::AXEvent> events, |
| ui::AXLocationAndScrollUpdates location_and_scroll_updates, |
| bool had_load_complete_messages); |
| |
| // Returns the main top-level document for this page, or NULL if there's |
| // no view or frame. |
| blink::WebDocument GetMainDocument() const; |
| |
| blink::WebAXContext* GetAXContext() { return ax_context_.get(); } |
| |
| // Returns the page language. |
| std::string GetLanguage(); |
| |
| // Access the UKM recorder. |
| ukm::MojoUkmRecorder* ukm_recorder() const { return ukm_recorder_.get(); } |
| |
| // Called when the renderer has closed the connection to reset the state |
| // machine. |
| void ConnectionClosed(); |
| |
| // The AxID of the first unlabeled image we have encountered in this tree. |
| // |
| // Used to ensure that the tutor message that explains to screen reader users |
| // how to turn on automatic image labels is provided only once. |
| mutable std::optional<int32_t> first_unlabeled_image_id_ = std::nullopt; |
| |
| // Whether we should highlight annotation results visually on the page |
| // for debugging. |
| bool image_annotation_debugging_ = false; |
| |
| AXAnnotatorsManager* ax_annotators_manager_for_testing() { |
| return ax_annotators_manager_.get(); |
| } |
| |
| private: |
| // Called whenever the "ack" message is received for a serialization message |
| // sent to the browser process, indicating it was received. |
| void OnSerializationReceived(); |
| |
| // RenderFrameObserver implementation. |
| void OnDestruct() override; |
| |
| // Handlers for messages from the browser to the renderer. |
| void OnLoadInlineTextBoxes(const ui::AXActionTarget* target); |
| void OnGetImageData(const ui::AXActionTarget* target, |
| const gfx::Size& max_size); |
| |
| // If the document is loaded, fire a load complete event. |
| void FireLoadCompleteIfLoaded(); |
| |
| // Marks all AXObjects with the given role in the current tree dirty. |
| void MarkAllAXObjectsDirty(ax::mojom::Role role, |
| ax::mojom::Action event_from_action); |
| |
| // Ensure that SendAccessibilitySerialization() will be called at the next |
| // available opportunity, so that any dirty objects will be serialized soon. |
| void ScheduleImmediateAXUpdate(); |
| |
| // Returns the document for the active popup if any. |
| blink::WebDocument GetPopupDocument(); |
| |
| blink::WebAXObject ComputeRoot(); |
| |
| // Sends the URL-keyed metrics for the maximum amount of time spent in |
| // SendPendingAccessibilityEvents if they meet the minimum criteria for |
| // sending. |
| void MaybeSendUKM(); |
| |
| // Reset all of the UKM data. This can be called after sending UKM data, |
| // or after navigating to a new page when any previous data will no |
| // longer be valid. |
| void ResetUKMData(); |
| |
| bool SerializeUpdatesAndEvents(blink::WebDocument document, |
| blink::WebAXObject root, |
| std::vector<ui::AXEvent>& events, |
| std::vector<ui::AXTreeUpdate>& updates); |
| |
| // The RenderAccessibilityManager that owns us. |
| raw_ptr<RenderAccessibilityManager> render_accessibility_manager_; |
| |
| // The associated RenderFrameImpl by means of the RenderAccessibilityManager. |
| raw_ptr<RenderFrameImpl> render_frame_; |
| |
| // This keeps accessibility enabled as long as it lives. |
| std::unique_ptr<blink::WebAXContext> ax_context_; |
| |
| // Manages generated annotations of the AXTree. |
| std::unique_ptr<AXAnnotatorsManager> ax_annotators_manager_; |
| |
| raw_ptr<PluginAXTreeActionTargetAdapter> plugin_action_target_adapter_; |
| |
| // Token to return this token in the next IPC, so that RenderFrameHostImpl |
| // can discard stale data, when the token does not match the expected token. |
| std::optional<uint32_t> reset_token_; |
| |
| // The specified page language, or empty if unknown. |
| std::string page_language_; |
| |
| // The URL-keyed metrics recorder interface. |
| std::unique_ptr<ukm::MojoUkmRecorder> ukm_recorder_; |
| |
| // The longest amount of time spent serializing the accessibility tree |
| // in SendPendingAccessibilityEvents. This is periodically uploaded as |
| // a UKM and then reset. |
| base::TimeDelta slowest_serialization_time_; |
| |
| // Tracks the stage in the loading process for a document, which is used to |
| // determine if serialization is part of the loading process or post load. |
| enum class LoadingStage { |
| // Expect to process a kLoadComplete event. |
| kPreload, |
| // kLoadComplete event has been processed and waiting on next AXReady call |
| // to indicate that we have completed processing all events associated with |
| // loading the document. |
| kLoadCompleted, |
| // All accessibility events associated with the initial document load have |
| // been serialized. |
| kPostLoad |
| }; |
| LoadingStage loading_stage_ = LoadingStage::kPreload; |
| |
| // The amount of time since the last UKM upload. |
| std::unique_ptr<base::ElapsedTimer> ukm_timer_; |
| |
| // The UKM Source ID that corresponds to the web page represented by |
| // slowest_serialization_ms_. We report UKM before the user navigates |
| // away, or every few minutes. |
| ukm::SourceId last_ukm_source_id_; |
| |
| // Note: this is the accessibility mode communicated to this object. |
| // The actual accessibility mode on a Document is the combination of this |
| // mode and any other active AXContext objects' accessibility modes. |
| ui::AXMode accessibility_mode_; |
| |
| // So we can queue up tasks to be executed later. |
| base::WeakPtrFactory<RenderAccessibilityImpl> |
| weak_factory_for_pending_events_{this}; |
| |
| friend class AXImageAnnotatorTest; |
| friend class PluginActionHandlingTest; |
| friend class RenderAccessibilityImplTest; |
| friend class RenderAccessibilityImplUKMTest; |
| }; |
| |
| } // namespace content |
| |
| #endif // CONTENT_RENDERER_ACCESSIBILITY_RENDER_ACCESSIBILITY_IMPL_H_ |