blob: 16e8fbc187d4bbc2365ab0fb5d9e49767f902d44 [file] [log] [blame]
/*
* Copyright (C) 2013, Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "third_party/blink/renderer/modules/accessibility/ax_inline_text_box.h"
#include "third_party/blink/renderer/core/dom/range.h"
#include "third_party/blink/renderer/core/layout/api/line_layout_api_shim.h"
#include "third_party/blink/renderer/core/layout/layout_text.h"
#include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h"
#include "third_party/blink/renderer/modules/accessibility/ax_position.h"
#include "third_party/blink/renderer/modules/accessibility/ax_range.h"
#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
namespace blink {
AXInlineTextBox::AXInlineTextBox(
scoped_refptr<AbstractInlineTextBox> inline_text_box,
AXObjectCacheImpl& ax_object_cache)
: AXObject(ax_object_cache), inline_text_box_(std::move(inline_text_box)) {}
void AXInlineTextBox::Init() {}
void AXInlineTextBox::Detach() {
AXObject::Detach();
inline_text_box_ = nullptr;
}
bool AXInlineTextBox::IsLineBreakingObject() const {
if (IsDetached())
return AXObject::IsLineBreakingObject();
// If this object is a forced line break, or the parent is a <br>
// element, then this object is line breaking.
const AXObject* parent = ParentObject();
return inline_text_box_->IsLineBreak() ||
(parent && parent->RoleValue() == ax::mojom::Role::kLineBreak);
}
void AXInlineTextBox::GetRelativeBounds(AXObject** out_container,
FloatRect& out_bounds_in_container,
SkMatrix44& out_container_transform,
bool* clips_children) const {
*out_container = nullptr;
out_bounds_in_container = FloatRect();
out_container_transform.setIdentity();
if (!inline_text_box_ || !ParentObject() ||
!ParentObject()->GetLayoutObject())
return;
*out_container = ParentObject();
out_bounds_in_container = FloatRect(inline_text_box_->LocalBounds());
// Subtract the local bounding box of the parent because they're
// both in the same coordinate system.
FloatRect parent_bounding_box =
ParentObject()->LocalBoundingBoxRectForAccessibility();
out_bounds_in_container.MoveBy(-parent_bounding_box.Location());
}
bool AXInlineTextBox::ComputeAccessibilityIsIgnored(
IgnoredReasons* ignored_reasons) const {
AXObject* parent = ParentObject();
if (!parent)
return false;
if (!parent->AccessibilityIsIgnored())
return false;
if (ignored_reasons)
parent->ComputeAccessibilityIsIgnored(ignored_reasons);
return true;
}
void AXInlineTextBox::TextCharacterOffsets(Vector<int>& offsets) const {
if (!inline_text_box_)
return;
unsigned len = inline_text_box_->Len();
Vector<float> widths;
inline_text_box_->CharacterWidths(widths);
DCHECK_EQ(widths.size(), len);
offsets.resize(len);
float width_so_far = 0;
for (unsigned i = 0; i < len; i++) {
width_so_far += widths[i];
offsets[i] = roundf(width_so_far);
}
}
void AXInlineTextBox::GetWordBoundaries(Vector<int>& word_starts,
Vector<int>& word_ends) const {
if (!inline_text_box_ ||
inline_text_box_->GetText().ContainsOnlyWhitespaceOrEmpty())
return;
Vector<AbstractInlineTextBox::WordBoundaries> boundaries;
inline_text_box_->GetWordBoundaries(boundaries);
word_starts.ReserveCapacity(boundaries.size());
word_ends.ReserveCapacity(boundaries.size());
for (const auto& boundary : boundaries) {
word_starts.push_back(boundary.start_index);
word_ends.push_back(boundary.end_index);
}
}
String AXInlineTextBox::GetName(ax::mojom::NameFrom& name_from,
AXObject::AXObjectVector* name_objects) const {
if (!inline_text_box_)
return String();
name_from = ax::mojom::NameFrom::kContents;
return inline_text_box_->GetText();
}
AXObject* AXInlineTextBox::ComputeParent() const {
DCHECK(!IsDetached());
if (!inline_text_box_ || !ax_object_cache_)
return nullptr;
LineLayoutText line_layout_text = inline_text_box_->GetLineLayoutItem();
if (!line_layout_text)
return nullptr;
return ax_object_cache_->GetOrCreate(
LineLayoutAPIShim::LayoutObjectFrom(line_layout_text));
}
// In addition to LTR and RTL direction, edit fields also support
// top to bottom and bottom to top via the CSS writing-mode property.
ax::mojom::TextDirection AXInlineTextBox::GetTextDirection() const {
if (!inline_text_box_)
return AXObject::GetTextDirection();
switch (inline_text_box_->GetDirection()) {
case AbstractInlineTextBox::kLeftToRight:
return ax::mojom::TextDirection::kLtr;
case AbstractInlineTextBox::kRightToLeft:
return ax::mojom::TextDirection::kRtl;
case AbstractInlineTextBox::kTopToBottom:
return ax::mojom::TextDirection::kTtb;
case AbstractInlineTextBox::kBottomToTop:
return ax::mojom::TextDirection::kBtt;
}
return AXObject::GetTextDirection();
}
Node* AXInlineTextBox::GetNode() const {
if (!inline_text_box_)
return nullptr;
return inline_text_box_->GetNode();
}
AXObject* AXInlineTextBox::NextOnLine() const {
if (inline_text_box_->IsLast())
return ParentObject()->NextOnLine();
scoped_refptr<AbstractInlineTextBox> next_on_line =
inline_text_box_->NextOnLine();
if (next_on_line)
return ax_object_cache_->GetOrCreate(next_on_line.get());
return nullptr;
}
AXObject* AXInlineTextBox::PreviousOnLine() const {
if (inline_text_box_->IsFirst())
return ParentObject()->PreviousOnLine();
scoped_refptr<AbstractInlineTextBox> previous_on_line =
inline_text_box_->PreviousOnLine();
if (previous_on_line)
return ax_object_cache_->GetOrCreate(previous_on_line.get());
return nullptr;
}
} // namespace blink