| /* |
| * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. |
| * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) |
| * Copyright (C) 2009 Igalia S.L. |
| * |
| * 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. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 COMPUTER, INC. OR |
| * 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. |
| */ |
| |
| // Copyright 2018 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/editing/commands/style_commands.h" |
| |
| #include "third_party/blink/renderer/core/css/css_computed_style_declaration.h" |
| #include "third_party/blink/renderer/core/css/css_identifier_value.h" |
| #include "third_party/blink/renderer/core/css/css_property_value_set.h" |
| #include "third_party/blink/renderer/core/css/css_value_list.h" |
| #include "third_party/blink/renderer/core/editing/commands/apply_style_command.h" |
| #include "third_party/blink/renderer/core/editing/editing_behavior.h" |
| #include "third_party/blink/renderer/core/editing/editing_style_utilities.h" |
| #include "third_party/blink/renderer/core/editing/editing_tri_state.h" |
| #include "third_party/blink/renderer/core/editing/editing_utilities.h" |
| #include "third_party/blink/renderer/core/editing/editor.h" |
| #include "third_party/blink/renderer/core/editing/ephemeral_range.h" |
| #include "third_party/blink/renderer/core/editing/frame_selection.h" |
| #include "third_party/blink/renderer/core/editing/visible_position.h" |
| #include "third_party/blink/renderer/core/editing/writing_direction.h" |
| #include "third_party/blink/renderer/core/frame/local_frame.h" |
| #include "third_party/blink/renderer/core/html/html_font_element.h" |
| |
| namespace blink { |
| |
| void StyleCommands::ApplyStyle(LocalFrame& frame, |
| CSSPropertyValueSet* style, |
| InputEvent::InputType input_type) { |
| const VisibleSelection& selection = |
| frame.Selection().ComputeVisibleSelectionInDOMTreeDeprecated(); |
| if (selection.IsNone()) |
| return; |
| if (selection.IsCaret()) { |
| frame.GetEditor().ComputeAndSetTypingStyle(style, input_type); |
| return; |
| } |
| DCHECK(selection.IsRange()) << selection; |
| if (!style) |
| return; |
| DCHECK(frame.GetDocument()); |
| ApplyStyleCommand::Create(*frame.GetDocument(), EditingStyle::Create(style), |
| input_type) |
| ->Apply(); |
| } |
| |
| void StyleCommands::ApplyStyleToSelection(LocalFrame& frame, |
| CSSPropertyValueSet* style, |
| InputEvent::InputType input_type) { |
| if (!style || style->IsEmpty() || !frame.GetEditor().CanEditRichly()) |
| return; |
| |
| ApplyStyle(frame, style, input_type); |
| } |
| |
| bool StyleCommands::ApplyCommandToFrame(LocalFrame& frame, |
| EditorCommandSource source, |
| InputEvent::InputType input_type, |
| CSSPropertyValueSet* style) { |
| // TODO(editnig-dev): We don't call shouldApplyStyle when the source is DOM; |
| // is there a good reason for that? |
| switch (source) { |
| case EditorCommandSource::kMenuOrKeyBinding: |
| ApplyStyleToSelection(frame, style, input_type); |
| return true; |
| case EditorCommandSource::kDOM: |
| ApplyStyle(frame, style, input_type); |
| return true; |
| } |
| NOTREACHED(); |
| return false; |
| } |
| |
| bool StyleCommands::ExecuteApplyStyle(LocalFrame& frame, |
| EditorCommandSource source, |
| InputEvent::InputType input_type, |
| CSSPropertyID property_id, |
| const String& property_value) { |
| DCHECK(frame.GetDocument()); |
| MutableCSSPropertyValueSet* const style = |
| MutableCSSPropertyValueSet::Create(kHTMLQuirksMode); |
| style->SetProperty(property_id, property_value, /* important */ false, |
| frame.GetDocument()->GetSecureContextMode()); |
| return ApplyCommandToFrame(frame, source, input_type, style); |
| } |
| |
| bool StyleCommands::ExecuteApplyStyle(LocalFrame& frame, |
| EditorCommandSource source, |
| InputEvent::InputType input_type, |
| CSSPropertyID property_id, |
| CSSValueID property_value) { |
| MutableCSSPropertyValueSet* const style = |
| MutableCSSPropertyValueSet::Create(kHTMLQuirksMode); |
| style->SetProperty(property_id, property_value); |
| return ApplyCommandToFrame(frame, source, input_type, style); |
| } |
| |
| bool StyleCommands::ExecuteBackColor(LocalFrame& frame, |
| Event*, |
| EditorCommandSource source, |
| const String& value) { |
| return ExecuteApplyStyle(frame, source, InputEvent::InputType::kNone, |
| CSSPropertyBackgroundColor, value); |
| } |
| |
| bool StyleCommands::ExecuteForeColor(LocalFrame& frame, |
| Event*, |
| EditorCommandSource source, |
| const String& value) { |
| return ExecuteApplyStyle(frame, source, InputEvent::InputType::kNone, |
| CSSPropertyColor, value); |
| } |
| |
| bool StyleCommands::ExecuteFontName(LocalFrame& frame, |
| Event*, |
| EditorCommandSource source, |
| const String& value) { |
| return ExecuteApplyStyle(frame, source, InputEvent::InputType::kNone, |
| CSSPropertyFontFamily, value); |
| } |
| |
| bool StyleCommands::ExecuteFontSize(LocalFrame& frame, |
| Event*, |
| EditorCommandSource source, |
| const String& value) { |
| CSSValueID size; |
| if (!HTMLFontElement::CssValueFromFontSizeNumber(value, size)) |
| return false; |
| return ExecuteApplyStyle(frame, source, InputEvent::InputType::kNone, |
| CSSPropertyFontSize, size); |
| } |
| |
| bool StyleCommands::ExecuteFontSizeDelta(LocalFrame& frame, |
| Event*, |
| EditorCommandSource source, |
| const String& value) { |
| return ExecuteApplyStyle(frame, source, InputEvent::InputType::kNone, |
| CSSPropertyWebkitFontSizeDelta, value); |
| } |
| |
| bool StyleCommands::ExecuteMakeTextWritingDirectionLeftToRight( |
| LocalFrame& frame, |
| Event*, |
| EditorCommandSource, |
| const String&) { |
| MutableCSSPropertyValueSet* const style = |
| MutableCSSPropertyValueSet::Create(kHTMLQuirksMode); |
| style->SetProperty(CSSPropertyUnicodeBidi, CSSValueIsolate); |
| style->SetProperty(CSSPropertyDirection, CSSValueLtr); |
| ApplyStyle(frame, style, InputEvent::InputType::kFormatSetBlockTextDirection); |
| return true; |
| } |
| |
| bool StyleCommands::ExecuteMakeTextWritingDirectionNatural(LocalFrame& frame, |
| Event*, |
| EditorCommandSource, |
| const String&) { |
| MutableCSSPropertyValueSet* const style = |
| MutableCSSPropertyValueSet::Create(kHTMLQuirksMode); |
| style->SetProperty(CSSPropertyUnicodeBidi, CSSValueNormal); |
| ApplyStyle(frame, style, InputEvent::InputType::kFormatSetBlockTextDirection); |
| return true; |
| } |
| |
| bool StyleCommands::ExecuteMakeTextWritingDirectionRightToLeft( |
| LocalFrame& frame, |
| Event*, |
| EditorCommandSource, |
| const String&) { |
| MutableCSSPropertyValueSet* const style = |
| MutableCSSPropertyValueSet::Create(kHTMLQuirksMode); |
| style->SetProperty(CSSPropertyUnicodeBidi, CSSValueIsolate); |
| style->SetProperty(CSSPropertyDirection, CSSValueRtl); |
| ApplyStyle(frame, style, InputEvent::InputType::kFormatSetBlockTextDirection); |
| return true; |
| } |
| |
| bool StyleCommands::SelectionStartHasStyle(LocalFrame& frame, |
| CSSPropertyID property_id, |
| const String& value) { |
| const SecureContextMode secure_context_mode = |
| frame.GetDocument()->GetSecureContextMode(); |
| |
| EditingStyle* const style_to_check = |
| EditingStyle::Create(property_id, value, secure_context_mode); |
| EditingStyle* const style_at_start = |
| EditingStyleUtilities::CreateStyleAtSelectionStart( |
| frame.Selection().ComputeVisibleSelectionInDOMTreeDeprecated(), |
| property_id == CSSPropertyBackgroundColor, style_to_check->Style()); |
| return style_to_check->TriStateOfStyle(style_at_start, secure_context_mode) != |
| EditingTriState::kFalse; |
| } |
| |
| bool StyleCommands::ExecuteToggleStyle(LocalFrame& frame, |
| EditorCommandSource source, |
| InputEvent::InputType input_type, |
| CSSPropertyID property_id, |
| const char* off_value, |
| const char* on_value) { |
| // Style is considered present when |
| // Mac: present at the beginning of selection |
| // other: present throughout the selection |
| const bool style_is_present = |
| frame.GetEditor().Behavior().ShouldToggleStyleBasedOnStartOfSelection() |
| ? SelectionStartHasStyle(frame, property_id, on_value) |
| : EditingStyle::SelectionHasStyle(frame, property_id, on_value) == |
| EditingTriState::kTrue; |
| |
| EditingStyle* const style = |
| EditingStyle::Create(property_id, style_is_present ? off_value : on_value, |
| frame.GetDocument()->GetSecureContextMode()); |
| return ApplyCommandToFrame(frame, source, input_type, style->Style()); |
| } |
| |
| bool StyleCommands::ExecuteToggleBold(LocalFrame& frame, |
| Event*, |
| EditorCommandSource source, |
| const String&) { |
| return ExecuteToggleStyle(frame, source, InputEvent::InputType::kFormatBold, |
| CSSPropertyFontWeight, "normal", "bold"); |
| } |
| |
| bool StyleCommands::ExecuteToggleItalic(LocalFrame& frame, |
| Event*, |
| EditorCommandSource source, |
| const String&) { |
| return ExecuteToggleStyle(frame, source, InputEvent::InputType::kFormatItalic, |
| CSSPropertyFontStyle, "normal", "italic"); |
| } |
| |
| bool StyleCommands::ExecuteSubscript(LocalFrame& frame, |
| Event*, |
| EditorCommandSource source, |
| const String&) { |
| return ExecuteToggleStyle(frame, source, |
| InputEvent::InputType::kFormatSubscript, |
| CSSPropertyVerticalAlign, "baseline", "sub"); |
| } |
| |
| bool StyleCommands::ExecuteSuperscript(LocalFrame& frame, |
| Event*, |
| EditorCommandSource source, |
| const String&) { |
| return ExecuteToggleStyle(frame, source, |
| InputEvent::InputType::kFormatSuperscript, |
| CSSPropertyVerticalAlign, "baseline", "super"); |
| } |
| |
| bool StyleCommands::ExecuteUnscript(LocalFrame& frame, |
| Event*, |
| EditorCommandSource source, |
| const String&) { |
| return ExecuteApplyStyle(frame, source, InputEvent::InputType::kNone, |
| CSSPropertyVerticalAlign, "baseline"); |
| } |
| |
| String StyleCommands::ComputeToggleStyleInList(EditingStyle& selection_style, |
| CSSPropertyID property_id, |
| const CSSValue& value) { |
| const CSSValue& selected_css_value = |
| *selection_style.Style()->GetPropertyCSSValue(property_id); |
| if (selected_css_value.IsValueList()) { |
| CSSValueList& selected_css_value_list = |
| *ToCSSValueList(selected_css_value).Copy(); |
| if (!selected_css_value_list.RemoveAll(value)) |
| selected_css_value_list.Append(value); |
| if (selected_css_value_list.length()) |
| return selected_css_value_list.CssText(); |
| } else if (selected_css_value.CssText() == "none") { |
| return value.CssText(); |
| } |
| return "none"; |
| } |
| |
| bool StyleCommands::ExecuteToggleStyleInList(LocalFrame& frame, |
| EditorCommandSource source, |
| InputEvent::InputType input_type, |
| CSSPropertyID property_id, |
| const CSSValue& value) { |
| EditingStyle* const selection_style = |
| EditingStyleUtilities::CreateStyleAtSelectionStart( |
| frame.Selection().ComputeVisibleSelectionInDOMTree()); |
| if (!selection_style || !selection_style->Style()) |
| return false; |
| |
| const String new_style = |
| ComputeToggleStyleInList(*selection_style, property_id, value); |
| |
| // TODO(editnig-dev): We shouldn't be having to convert new style into text. |
| // We should have setPropertyCSSValue. |
| MutableCSSPropertyValueSet* const new_mutable_style = |
| MutableCSSPropertyValueSet::Create(kHTMLQuirksMode); |
| new_mutable_style->SetProperty(property_id, new_style, /* important */ false, |
| frame.GetDocument()->GetSecureContextMode()); |
| return ApplyCommandToFrame(frame, source, input_type, new_mutable_style); |
| } |
| |
| bool StyleCommands::ExecuteStrikethrough(LocalFrame& frame, |
| Event*, |
| EditorCommandSource source, |
| const String&) { |
| const CSSIdentifierValue& line_through = |
| *CSSIdentifierValue::Create(CSSValueLineThrough); |
| return ExecuteToggleStyleInList( |
| frame, source, InputEvent::InputType::kFormatStrikeThrough, |
| CSSPropertyWebkitTextDecorationsInEffect, line_through); |
| } |
| |
| bool StyleCommands::ExecuteUnderline(LocalFrame& frame, |
| Event*, |
| EditorCommandSource source, |
| const String&) { |
| const CSSIdentifierValue& underline = |
| *CSSIdentifierValue::Create(CSSValueUnderline); |
| return ExecuteToggleStyleInList( |
| frame, source, InputEvent::InputType::kFormatUnderline, |
| CSSPropertyWebkitTextDecorationsInEffect, underline); |
| } |
| |
| bool StyleCommands::ExecuteStyleWithCSS(LocalFrame& frame, |
| Event*, |
| EditorCommandSource, |
| const String& value) { |
| frame.GetEditor().SetShouldStyleWithCSS( |
| !DeprecatedEqualIgnoringCase(value, "false")); |
| return true; |
| } |
| |
| bool StyleCommands::ExecuteUseCSS(LocalFrame& frame, |
| Event*, |
| EditorCommandSource, |
| const String& value) { |
| frame.GetEditor().SetShouldStyleWithCSS( |
| DeprecatedEqualIgnoringCase(value, "false")); |
| return true; |
| } |
| |
| // State functions |
| EditingTriState StyleCommands::StateStyle(LocalFrame& frame, |
| CSSPropertyID property_id, |
| const char* desired_value) { |
| frame.GetDocument()->UpdateStyleAndLayoutIgnorePendingStylesheets(); |
| if (frame.GetEditor().Behavior().ShouldToggleStyleBasedOnStartOfSelection()) { |
| return SelectionStartHasStyle(frame, property_id, desired_value) |
| ? EditingTriState::kTrue |
| : EditingTriState::kFalse; |
| } |
| return EditingStyle::SelectionHasStyle(frame, property_id, desired_value); |
| } |
| |
| EditingTriState StyleCommands::StateBold(LocalFrame& frame, Event*) { |
| return StateStyle(frame, CSSPropertyFontWeight, "bold"); |
| } |
| |
| EditingTriState StyleCommands::StateItalic(LocalFrame& frame, Event*) { |
| return StateStyle(frame, CSSPropertyFontStyle, "italic"); |
| } |
| |
| EditingTriState StyleCommands::StateStrikethrough(LocalFrame& frame, Event*) { |
| return StateStyle(frame, CSSPropertyWebkitTextDecorationsInEffect, |
| "line-through"); |
| } |
| |
| EditingTriState StyleCommands::StateStyleWithCSS(LocalFrame& frame, Event*) { |
| return frame.GetEditor().ShouldStyleWithCSS() ? EditingTriState::kTrue |
| : EditingTriState::kFalse; |
| } |
| |
| EditingTriState StyleCommands::StateSubscript(LocalFrame& frame, Event*) { |
| return StateStyle(frame, CSSPropertyVerticalAlign, "sub"); |
| } |
| |
| EditingTriState StyleCommands::StateSuperscript(LocalFrame& frame, Event*) { |
| return StateStyle(frame, CSSPropertyVerticalAlign, "super"); |
| } |
| |
| bool StyleCommands::IsUnicodeBidiNestedOrMultipleEmbeddings( |
| CSSValueID value_id) { |
| return value_id == CSSValueEmbed || value_id == CSSValueBidiOverride || |
| value_id == CSSValueWebkitIsolate || |
| value_id == CSSValueWebkitIsolateOverride || |
| value_id == CSSValueWebkitPlaintext || value_id == CSSValueIsolate || |
| value_id == CSSValueIsolateOverride || value_id == CSSValuePlaintext; |
| } |
| |
| WritingDirection StyleCommands::TextDirectionForSelection( |
| const VisibleSelection& selection, |
| EditingStyle* typing_style, |
| bool& has_nested_or_multiple_embeddings) { |
| has_nested_or_multiple_embeddings = true; |
| |
| if (selection.IsNone()) |
| return WritingDirection::kNatural; |
| |
| const Position position = MostForwardCaretPosition(selection.Start()); |
| |
| const Node* anchor_node = position.AnchorNode(); |
| if (!anchor_node) |
| return WritingDirection::kNatural; |
| |
| Position end; |
| if (selection.IsRange()) { |
| end = MostBackwardCaretPosition(selection.End()); |
| |
| DCHECK(end.GetDocument()); |
| const EphemeralRange caret_range(position.ParentAnchoredEquivalent(), |
| end.ParentAnchoredEquivalent()); |
| for (Node& node : caret_range.Nodes()) { |
| if (!node.IsStyledElement()) |
| continue; |
| |
| const CSSComputedStyleDeclaration& style = |
| *CSSComputedStyleDeclaration::Create(&node); |
| const CSSValue* unicode_bidi = |
| style.GetPropertyCSSValue(GetCSSPropertyUnicodeBidi()); |
| if (!unicode_bidi || !unicode_bidi->IsIdentifierValue()) |
| continue; |
| |
| const CSSValueID unicode_bidi_value = |
| ToCSSIdentifierValue(unicode_bidi)->GetValueID(); |
| if (IsUnicodeBidiNestedOrMultipleEmbeddings(unicode_bidi_value)) |
| return WritingDirection::kNatural; |
| } |
| } |
| |
| if (selection.IsCaret()) { |
| WritingDirection direction; |
| if (typing_style && typing_style->GetTextDirection(direction)) { |
| has_nested_or_multiple_embeddings = false; |
| return direction; |
| } |
| anchor_node = selection.VisibleStart().DeepEquivalent().AnchorNode(); |
| } |
| DCHECK(anchor_node); |
| |
| // The selection is either a caret with no typing attributes or a range in |
| // which no embedding is added, so just use the start position to decide. |
| const Node* block = EnclosingBlock(anchor_node); |
| WritingDirection found_direction = WritingDirection::kNatural; |
| |
| for (Node& runner : NodeTraversal::InclusiveAncestorsOf(*anchor_node)) { |
| if (runner == block) |
| break; |
| if (!runner.IsStyledElement()) |
| continue; |
| |
| Element* element = &ToElement(runner); |
| const CSSComputedStyleDeclaration& style = |
| *CSSComputedStyleDeclaration::Create(element); |
| const CSSValue* unicode_bidi = |
| style.GetPropertyCSSValue(GetCSSPropertyUnicodeBidi()); |
| if (!unicode_bidi || !unicode_bidi->IsIdentifierValue()) |
| continue; |
| |
| const CSSValueID unicode_bidi_value = |
| ToCSSIdentifierValue(unicode_bidi)->GetValueID(); |
| if (unicode_bidi_value == CSSValueNormal) |
| continue; |
| |
| if (unicode_bidi_value == CSSValueBidiOverride) |
| return WritingDirection::kNatural; |
| |
| DCHECK(EditingStyleUtilities::IsEmbedOrIsolate(unicode_bidi_value)) |
| << unicode_bidi_value; |
| const CSSValue* direction = |
| style.GetPropertyCSSValue(GetCSSPropertyDirection()); |
| if (!direction || !direction->IsIdentifierValue()) |
| continue; |
| |
| const int direction_value = ToCSSIdentifierValue(direction)->GetValueID(); |
| if (direction_value != CSSValueLtr && direction_value != CSSValueRtl) |
| continue; |
| |
| if (found_direction != WritingDirection::kNatural) |
| return WritingDirection::kNatural; |
| |
| // In the range case, make sure that the embedding element persists until |
| // the end of the range. |
| if (selection.IsRange() && !end.AnchorNode()->IsDescendantOf(element)) |
| return WritingDirection::kNatural; |
| |
| found_direction = direction_value == CSSValueLtr |
| ? WritingDirection::kLeftToRight |
| : WritingDirection::kRightToLeft; |
| } |
| has_nested_or_multiple_embeddings = false; |
| return found_direction; |
| } |
| |
| EditingTriState StyleCommands::StateTextWritingDirection( |
| LocalFrame& frame, |
| WritingDirection direction) { |
| frame.GetDocument()->UpdateStyleAndLayoutIgnorePendingStylesheets(); |
| |
| bool has_nested_or_multiple_embeddings; |
| WritingDirection selection_direction = TextDirectionForSelection( |
| frame.Selection().ComputeVisibleSelectionInDOMTreeDeprecated(), |
| frame.GetEditor().TypingStyle(), has_nested_or_multiple_embeddings); |
| // TODO(editnig-dev): We should be returning MixedTriState when |
| // selectionDirection == direction && hasNestedOrMultipleEmbeddings |
| return (selection_direction == direction && |
| !has_nested_or_multiple_embeddings) |
| ? EditingTriState::kTrue |
| : EditingTriState::kFalse; |
| } |
| |
| EditingTriState StyleCommands::StateTextWritingDirectionLeftToRight( |
| LocalFrame& frame, |
| Event*) { |
| return StateTextWritingDirection(frame, WritingDirection::kLeftToRight); |
| } |
| |
| EditingTriState StyleCommands::StateTextWritingDirectionNatural( |
| LocalFrame& frame, |
| Event*) { |
| return StateTextWritingDirection(frame, WritingDirection::kNatural); |
| } |
| |
| EditingTriState StyleCommands::StateTextWritingDirectionRightToLeft( |
| LocalFrame& frame, |
| Event*) { |
| return StateTextWritingDirection(frame, WritingDirection::kRightToLeft); |
| } |
| |
| EditingTriState StyleCommands::StateUnderline(LocalFrame& frame, Event*) { |
| return StateStyle(frame, CSSPropertyWebkitTextDecorationsInEffect, |
| "underline"); |
| } |
| |
| // Value functions |
| String StyleCommands::SelectionStartCSSPropertyValue( |
| LocalFrame& frame, |
| CSSPropertyID property_id) { |
| EditingStyle* const selection_style = |
| EditingStyleUtilities::CreateStyleAtSelectionStart( |
| frame.Selection().ComputeVisibleSelectionInDOMTreeDeprecated(), |
| property_id == CSSPropertyBackgroundColor); |
| if (!selection_style || !selection_style->Style()) |
| return String(); |
| |
| if (property_id == CSSPropertyFontSize) |
| return String::Number(selection_style->LegacyFontSize(frame.GetDocument())); |
| return selection_style->Style()->GetPropertyValue(property_id); |
| } |
| |
| String StyleCommands::ValueStyle(LocalFrame& frame, CSSPropertyID property_id) { |
| frame.GetDocument()->UpdateStyleAndLayoutIgnorePendingStylesheets(); |
| |
| // TODO(editnig-dev): Rather than retrieving the style at the start of the |
| // current selection, we should retrieve the style present throughout the |
| // selection for non-Mac platforms. |
| return SelectionStartCSSPropertyValue(frame, property_id); |
| } |
| |
| String StyleCommands::ValueBackColor(const EditorInternalCommand&, |
| LocalFrame& frame, |
| Event*) { |
| return ValueStyle(frame, CSSPropertyBackgroundColor); |
| } |
| |
| String StyleCommands::ValueForeColor(const EditorInternalCommand&, |
| LocalFrame& frame, |
| Event*) { |
| return ValueStyle(frame, CSSPropertyColor); |
| } |
| |
| String StyleCommands::ValueFontName(const EditorInternalCommand&, |
| LocalFrame& frame, |
| Event*) { |
| return ValueStyle(frame, CSSPropertyFontFamily); |
| } |
| |
| String StyleCommands::ValueFontSize(const EditorInternalCommand&, |
| LocalFrame& frame, |
| Event*) { |
| return ValueStyle(frame, CSSPropertyFontSize); |
| } |
| |
| String StyleCommands::ValueFontSizeDelta(const EditorInternalCommand&, |
| LocalFrame& frame, |
| Event*) { |
| return ValueStyle(frame, CSSPropertyWebkitFontSizeDelta); |
| } |
| |
| } // namespace blink |