1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #ifndef mozilla_CSSEditUtils_h 7 #define mozilla_CSSEditUtils_h 8 9 #include "mozilla/ChangeStyleTransaction.h" // for ChangeStyleTransaction 10 #include "nsCOMPtr.h" // for already_AddRefed 11 #include "nsStringFwd.h" 12 #include "nsTArray.h" // for nsTArray 13 #include "nscore.h" // for nsAString, nsresult, nullptr 14 15 class nsComputedDOMStyle; 16 class nsAtom; 17 class nsIContent; 18 class nsICSSDeclaration; 19 class nsINode; 20 class nsStaticAtom; 21 class nsStyledElement; 22 23 namespace mozilla { 24 25 class HTMLEditor; 26 namespace dom { 27 class Element; 28 } // namespace dom 29 30 typedef void (*nsProcessValueFunc)(const nsAString* aInputString, 31 nsAString& aOutputString, 32 const char* aDefaultValueString, 33 const char* aPrependString, 34 const char* aAppendString); 35 36 class CSSEditUtils final { 37 public: 38 explicit CSSEditUtils(HTMLEditor* aEditor); 39 40 enum nsCSSEditableProperty { 41 eCSSEditableProperty_NONE = 0, 42 eCSSEditableProperty_background_color, 43 eCSSEditableProperty_background_image, 44 eCSSEditableProperty_border, 45 eCSSEditableProperty_caption_side, 46 eCSSEditableProperty_color, 47 eCSSEditableProperty_float, 48 eCSSEditableProperty_font_family, 49 eCSSEditableProperty_font_size, 50 eCSSEditableProperty_font_style, 51 eCSSEditableProperty_font_weight, 52 eCSSEditableProperty_height, 53 eCSSEditableProperty_list_style_type, 54 eCSSEditableProperty_margin_left, 55 eCSSEditableProperty_margin_right, 56 eCSSEditableProperty_text_align, 57 eCSSEditableProperty_text_decoration, 58 eCSSEditableProperty_vertical_align, 59 eCSSEditableProperty_whitespace, 60 eCSSEditableProperty_width 61 }; 62 63 // Nb: keep these fields in an order that minimizes padding. 64 struct CSSEquivTable { 65 nsCSSEditableProperty cssProperty; 66 bool gettable; 67 bool caseSensitiveValue; 68 nsProcessValueFunc processValueFunctor; 69 const char* defaultValue; 70 const char* prependValue; 71 const char* appendValue; 72 }; 73 74 /** 75 * Answers true if the given combination element_name/attribute_name 76 * has a CSS equivalence in this implementation. 77 * 78 * @param aNode [IN] A DOM node. 79 * @param aProperty [IN] An atom containing a HTML tag name. 80 * @param aAttribute [IN] An atom containing a HTML 81 * attribute carried by the element above. 82 * @return A boolean saying if the tag/attribute has a CSS 83 * equiv. 84 */ 85 static bool IsCSSEditableProperty(nsINode* aNode, nsAtom* aProperty, 86 nsAtom* aAttribute); 87 88 /** 89 * Adds/remove a CSS declaration to the STYLE attribute carried by a given 90 * element. 91 * 92 * @param aStyledElement [IN] A DOM styled element. 93 * @param aProperty [IN] An atom containing the CSS property to set. 94 * @param aValue [IN] A string containing the value of the CSS 95 * property. 96 */ 97 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult SetCSSPropertyWithTransaction(nsStyledElement & aStyledElement,nsAtom & aProperty,const nsAString & aValue)98 SetCSSPropertyWithTransaction(nsStyledElement& aStyledElement, 99 nsAtom& aProperty, const nsAString& aValue) { 100 return SetCSSPropertyInternal(aStyledElement, aProperty, aValue, false); 101 } 102 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult SetCSSPropertyPixelsWithTransaction( 103 nsStyledElement& aStyledElement, nsAtom& aProperty, int32_t aIntValue); 104 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult 105 SetCSSPropertyPixelsWithoutTransaction(nsStyledElement& aStyledElement, 106 const nsAtom& aProperty, 107 int32_t aIntValue); RemoveCSSPropertyWithTransaction(nsStyledElement & aStyledElement,nsAtom & aProperty,const nsAString & aPropertyValue)108 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult RemoveCSSPropertyWithTransaction( 109 nsStyledElement& aStyledElement, nsAtom& aProperty, 110 const nsAString& aPropertyValue) { 111 return RemoveCSSPropertyInternal(aStyledElement, aProperty, aPropertyValue, 112 false); 113 } 114 115 /** 116 * Gets the specified/computed style value of a CSS property for a given 117 * node (or its element ancestor if it is not an element). 118 * 119 * @param aContent [IN] A DOM node. 120 * @param aProperty [IN] An atom containing the CSS property to get. 121 * @param aPropertyValue [OUT] The retrieved value of the property. 122 */ 123 static nsresult GetSpecifiedProperty(nsIContent& aContent, 124 nsAtom& aCSSProperty, nsAString& aValue); 125 MOZ_CAN_RUN_SCRIPT static nsresult GetComputedProperty(nsIContent& aContent, 126 nsAtom& aCSSProperty, 127 nsAString& aValue); 128 129 /** 130 * Removes a CSS property from the specified declarations in STYLE attribute 131 * and removes the node if it is an useless span. 132 * 133 * @param aStyledElement [IN] The styled element we want to remove a style 134 * from. 135 * @param aProperty [IN] The CSS property atom to remove. 136 * @param aPropertyValue [IN] The value of the property we have to remove 137 * if the property accepts more than one value. 138 */ 139 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult RemoveCSSInlineStyleWithTransaction( 140 nsStyledElement& aStyledElement, nsAtom* aProperty, 141 const nsAString& aPropertyValue); 142 143 /** 144 * Answers true is the property can be removed by setting a "none" CSS value 145 * on a node. 146 * 147 * @param aProperty [IN] An atom containing a CSS property. 148 * @param aAttribute [IN] Pointer to an attribute name or null if this 149 * information is irrelevant. 150 * @return A boolean saying if the property can be remove by 151 * setting a "none" value. 152 */ 153 static bool IsCSSInvertible(nsAtom& aProperty, nsAtom* aAttribute); 154 155 /** 156 * Get the default browser background color if we need it for 157 * GetCSSBackgroundColorState(). 158 * 159 * @param aColor [OUT] The default color as it is defined in prefs. 160 */ 161 static void GetDefaultBackgroundColor(nsAString& aColor); 162 163 /** 164 * Get the default length unit used for CSS Indent/Outdent. 165 * 166 * @param aLengthUnit [OUT] The default length unit as it is defined in 167 * prefs. 168 */ 169 static void GetDefaultLengthUnit(nsAString& aLengthUnit); 170 171 /** 172 * Returns the list of values for the CSS equivalences to 173 * the passed HTML style for the passed node. 174 * 175 * @param aContent [IN] A DOM node. 176 * @param aHTMLProperty [IN] An atom containing an HTML property. 177 * @param aAttribute [IN] An atom of attribute name or nullptr if 178 * irrelevant. 179 * @param aValueString [OUT] The list of CSS values. 180 */ 181 MOZ_CAN_RUN_SCRIPT static nsresult GetComputedCSSEquivalentToHTMLInlineStyleSet(nsIContent & aContent,nsAtom * aHTMLProperty,nsAtom * aAttribute,nsAString & aValue)182 GetComputedCSSEquivalentToHTMLInlineStyleSet(nsIContent& aContent, 183 nsAtom* aHTMLProperty, 184 nsAtom* aAttribute, 185 nsAString& aValue) { 186 return GetCSSEquivalentToHTMLInlineStyleSetInternal( 187 aContent, aHTMLProperty, aAttribute, aValue, StyleType::Computed); 188 } 189 190 /** 191 * Does the node aNode (or his parent if it is not an element node) carries 192 * the CSS equivalent styles to the HTML style for this node ? 193 * 194 * @param aContent [IN] A DOM node. 195 * @param aHTMLProperty [IN] An atom containing an HTML property. 196 * @param aAttribute [IN] A pointer/atom to an attribute name or nullptr 197 * if irrelevant. 198 * @param aValueString [IN/OUT] The attribute value (in) the list of CSS 199 * values (out). 200 * @return A boolean being true if the css properties are 201 * not same as initial value. 202 */ IsComputedCSSEquivalentToHTMLInlineStyleSet(nsIContent & aContent,nsAtom * aHTMLProperty,nsAtom * aAttribute,nsAString & aValue)203 MOZ_CAN_RUN_SCRIPT static bool IsComputedCSSEquivalentToHTMLInlineStyleSet( 204 nsIContent& aContent, nsAtom* aHTMLProperty, nsAtom* aAttribute, 205 nsAString& aValue) { 206 MOZ_ASSERT(aHTMLProperty || aAttribute); 207 return IsCSSEquivalentToHTMLInlineStyleSetInternal( 208 aContent, aHTMLProperty, aAttribute, aValue, StyleType::Computed); 209 } 210 MOZ_CAN_RUN_SCRIPT_BOUNDARY static bool IsSpecifiedCSSEquivalentToHTMLInlineStyleSet(nsIContent & aContent,nsAtom * aHTMLProperty,nsAtom * aAttribute,nsAString & aValue)211 IsSpecifiedCSSEquivalentToHTMLInlineStyleSet(nsIContent& aContent, 212 nsAtom* aHTMLProperty, 213 nsAtom* aAttribute, 214 nsAString& aValue) { 215 MOZ_ASSERT(aHTMLProperty || aAttribute); 216 return IsCSSEquivalentToHTMLInlineStyleSetInternal( 217 aContent, aHTMLProperty, aAttribute, aValue, StyleType::Specified); 218 } 219 220 /** 221 * This is a kind of IsCSSEquivalentToHTMLInlineStyleSet. 222 * IsCSSEquivalentToHTMLInlineStyleSet returns whether the properties 223 * aren't same as initial value. But this method returns whether the 224 * properties aren't set. 225 * If node is <span style="font-weight: normal"/>, 226 * - Is(Computed|Specified)CSSEquivalentToHTMLInlineStyleSet returns false. 227 * - Have(Computed|Specified)CSSEquivalentStyles returns true. 228 * 229 * @param aContent [IN] A DOM node. 230 * @param aHTMLProperty [IN] An atom containing an HTML property. 231 * @param aAttribute [IN] An atom to an attribute name or nullptr 232 * if irrelevant. 233 * @return A boolean being true if the css properties are 234 * not set. 235 */ HaveComputedCSSEquivalentStyles(nsIContent & aContent,nsAtom * aHTMLProperty,nsAtom * aAttribute)236 MOZ_CAN_RUN_SCRIPT static bool HaveComputedCSSEquivalentStyles( 237 nsIContent& aContent, nsAtom* aHTMLProperty, nsAtom* aAttribute) { 238 MOZ_ASSERT(aHTMLProperty || aAttribute); 239 return HaveCSSEquivalentStylesInternal(aContent, aHTMLProperty, aAttribute, 240 StyleType::Computed); 241 } HaveSpecifiedCSSEquivalentStyles(nsIContent & aContent,nsAtom * aHTMLProperty,nsAtom * aAttribute)242 MOZ_CAN_RUN_SCRIPT_BOUNDARY static bool HaveSpecifiedCSSEquivalentStyles( 243 nsIContent& aContent, nsAtom* aHTMLProperty, nsAtom* aAttribute) { 244 MOZ_ASSERT(aHTMLProperty || aAttribute); 245 return HaveCSSEquivalentStylesInternal(aContent, aHTMLProperty, aAttribute, 246 StyleType::Specified); 247 } 248 249 /** 250 * Adds to the node the CSS inline styles equivalent to the HTML style 251 * and return the number of CSS properties set by the call. 252 * 253 * @param aNode [IN] A DOM node. 254 * @param aHTMLProperty [IN] An atom containing an HTML property. 255 * @param aAttribute [IN] An atom to an attribute name or nullptr 256 * if irrelevant. 257 * @param aValue [IN] The attribute value. 258 * 259 * @return The number of CSS properties set by the call. 260 */ 261 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<int32_t, nsresult> SetCSSEquivalentToHTMLStyleWithTransaction(nsStyledElement & aStyledElement,nsAtom * aProperty,nsAtom * aAttribute,const nsAString * aValue)262 SetCSSEquivalentToHTMLStyleWithTransaction(nsStyledElement& aStyledElement, 263 nsAtom* aProperty, 264 nsAtom* aAttribute, 265 const nsAString* aValue) { 266 return SetCSSEquivalentToHTMLStyleInternal(aStyledElement, aProperty, 267 aAttribute, aValue, false); 268 } 269 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<int32_t, nsresult> SetCSSEquivalentToHTMLStyleWithoutTransaction(nsStyledElement & aStyledElement,nsAtom * aProperty,nsAtom * aAttribute,const nsAString * aValue)270 SetCSSEquivalentToHTMLStyleWithoutTransaction(nsStyledElement& aStyledElement, 271 nsAtom* aProperty, 272 nsAtom* aAttribute, 273 const nsAString* aValue) { 274 return SetCSSEquivalentToHTMLStyleInternal(aStyledElement, aProperty, 275 aAttribute, aValue, true); 276 } 277 278 /** 279 * Removes from the node the CSS inline styles equivalent to the HTML style. 280 * 281 * @param aStyledElement [IN] A DOM Element (must not be null). 282 * @param aHTMLProperty [IN] An atom containing an HTML property. 283 * @param aAttribute [IN] An atom to an attribute name or nullptr if 284 * irrelevant. 285 * @param aValue [IN] The attribute value. 286 */ 287 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult RemoveCSSEquivalentToHTMLStyleWithTransaction(nsStyledElement & aStyledElement,nsAtom * aHTMLProperty,nsAtom * aAttribute,const nsAString * aValue)288 RemoveCSSEquivalentToHTMLStyleWithTransaction(nsStyledElement& aStyledElement, 289 nsAtom* aHTMLProperty, 290 nsAtom* aAttribute, 291 const nsAString* aValue) { 292 return RemoveCSSEquivalentToHTMLStyleInternal(aStyledElement, aHTMLProperty, 293 aAttribute, aValue, false); 294 } 295 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult RemoveCSSEquivalentToHTMLStyleWithoutTransaction(nsStyledElement & aStyledElement,nsAtom * aHTMLProperty,nsAtom * aAttribute,const nsAString * aValue)296 RemoveCSSEquivalentToHTMLStyleWithoutTransaction( 297 nsStyledElement& aStyledElement, nsAtom* aHTMLProperty, 298 nsAtom* aAttribute, const nsAString* aValue) { 299 return RemoveCSSEquivalentToHTMLStyleInternal(aStyledElement, aHTMLProperty, 300 aAttribute, aValue, true); 301 } 302 303 /** 304 * Parses a "xxxx.xxxxxuuu" string where x is a digit and u an alpha char. 305 * 306 * @param aString [IN] Input string to parse. 307 * @param aValue [OUT] Numeric part. 308 * @param aUnit [OUT] Unit part. 309 */ 310 static void ParseLength(const nsAString& aString, float* aValue, 311 nsAtom** aUnit); 312 313 /** 314 * Sets the mIsCSSPrefChecked private member; used as callback from observer 315 * when the CSS pref state is changed. 316 * 317 * @param aIsCSSPrefChecked [IN] The new boolean state for the pref. 318 */ 319 void SetCSSEnabled(bool aIsCSSPrefChecked); 320 321 /** 322 * Retrieves the mIsCSSPrefChecked private member, true if the CSS pref is 323 * checked, false if it is not. 324 * 325 * @return the boolean value of the CSS pref. 326 */ 327 bool IsCSSPrefChecked() const; 328 329 /** 330 * DoStyledElementsHaveSameStyle compares two elements and checks if they have 331 * the same specified CSS declarations in the STYLE attribute. The answer is 332 * always false if at least one of them carries an ID or a class. 333 * 334 * @param aStyledElement [IN] A styled element. 335 * @param aOtherStyledElement [IN] The other styled element. 336 * @return true if the two elements are considered to 337 * have same styles. 338 */ 339 static bool DoStyledElementsHaveSameStyle( 340 nsStyledElement& aStyledElement, nsStyledElement& aOtherStyledElement); 341 342 public: 343 /** 344 * Gets the computed style for a given element. Can return null. 345 */ 346 static already_AddRefed<nsComputedDOMStyle> GetComputedStyle( 347 dom::Element* aElement); 348 349 private: 350 enum class StyleType { Specified, Computed }; 351 352 /** 353 * Retrieves the CSS property atom from an enum. 354 * 355 * @param aProperty The enum value for the property. 356 * @return The corresponding atom. 357 */ 358 static nsStaticAtom* GetCSSPropertyAtom(nsCSSEditableProperty aProperty); 359 360 /** 361 * Retrieves the CSS declarations equivalent to a HTML style value for 362 * a given equivalence table. 363 * 364 * @param aOutArrayOfCSSProperty [OUT] The array of css properties. 365 * @param aOutArrayOfCSSValue [OUT] The array of values for the CSS 366 * properties above. 367 * @param aEquivTable The equivalence table. 368 * @param aValue The HTML style value. 369 * @param aGetOrRemoveRequest A boolean value being true if the call to 370 * the current method is made for 371 * Get*CSSEquivalentToHTMLInlineStyleSet() 372 * or 373 * RemoveCSSEquivalentToHTMLInlineStyleSet(). 374 */ 375 static void BuildCSSDeclarations( 376 nsTArray<nsStaticAtom*>& aOutArrayOfCSSProperty, 377 nsTArray<nsString>& aOutArrayOfCSSValue, const CSSEquivTable* aEquivTable, 378 const nsAString* aValue, bool aGetOrRemoveRequest); 379 380 /** 381 * Retrieves the CSS declarations equivalent to the given HTML 382 * property/attribute/value for a given node. 383 * 384 * @param aElement The DOM node. 385 * @param aHTMLProperty An atom containing an HTML property. 386 * @param aAttribute An atom to an attribute name or nullptr 387 * if irrelevant 388 * @param aValue The attribute value. 389 * @param aOutArrayOfCSSProperty [OUT] The array of CSS properties. 390 * @param aOutArrayOfCSSValue [OUT] The array of values for the CSS 391 * properties above. 392 * @param aGetOrRemoveRequest A boolean value being true if the call to 393 * the current method is made for 394 * Get*CSSEquivalentToHTMLInlineStyleSet() or 395 * RemoveCSSEquivalentToHTMLInlineStyleSet(). 396 */ 397 static void GenerateCSSDeclarationsFromHTMLStyle( 398 dom::Element& aElement, nsAtom* aHTMLProperty, nsAtom* aAttribute, 399 const nsAString* aValue, nsTArray<nsStaticAtom*>& aOutArrayOfCSSProperty, 400 nsTArray<nsString>& aOutArrayOfCSSValue, bool aGetOrRemoveRequest); 401 402 /** 403 * Back-end for GetSpecifiedProperty and GetComputedProperty. 404 * 405 * @param aNode [IN] A DOM node. 406 * @param aProperty [IN] A CSS property. 407 * @param aValue [OUT] The retrieved value for this property. 408 */ 409 MOZ_CAN_RUN_SCRIPT static nsresult GetComputedCSSInlinePropertyBase( 410 nsIContent& aContent, nsAtom& aCSSProperty, nsAString& aValue); 411 static nsresult GetSpecifiedCSSInlinePropertyBase(nsIContent& aContent, 412 nsAtom& aCSSProperty, 413 nsAString& aValue); 414 415 /** 416 * Those methods are wrapped with corresponding methods which do not have 417 * "Internal" in their names. Don't use these methods directly even if 418 * you want to use one of them in this class. 419 * Note that these methods may run scrip only when StyleType is Computed. 420 */ 421 MOZ_CAN_RUN_SCRIPT static nsresult 422 GetCSSEquivalentToHTMLInlineStyleSetInternal(nsIContent& aContent, 423 nsAtom* aHTMLProperty, 424 nsAtom* aAttribute, 425 nsAString& aValue, 426 StyleType aStyleType); 427 MOZ_CAN_RUN_SCRIPT static bool IsCSSEquivalentToHTMLInlineStyleSetInternal( 428 nsIContent& aContent, nsAtom* aHTMLProperty, nsAtom* aAttribute, 429 nsAString& aValue, StyleType aStyleType); 430 MOZ_CAN_RUN_SCRIPT static bool HaveCSSEquivalentStylesInternal( 431 nsIContent& aContent, nsAtom* aHTMLProperty, nsAtom* aAttribute, 432 StyleType aStyleType); 433 434 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult RemoveCSSPropertyInternal( 435 nsStyledElement& aStyledElement, nsAtom& aProperty, 436 const nsAString& aPropertyValue, bool aSuppressTxn = false); 437 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult 438 RemoveCSSEquivalentToHTMLStyleInternal(nsStyledElement& aStyledElement, 439 nsAtom* aHTMLProperty, 440 nsAtom* aAttribute, 441 const nsAString* aValue, 442 bool aSuppressTransaction); 443 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult 444 SetCSSPropertyInternal(nsStyledElement& aStyledElement, nsAtom& aProperty, 445 const nsAString& aValue, bool aSuppressTxn = false); 446 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<int32_t, nsresult> 447 SetCSSEquivalentToHTMLStyleInternal(nsStyledElement& aStyledElement, 448 nsAtom* aProperty, nsAtom* aAttribute, 449 const nsAString* aValue, 450 bool aSuppressTransaction); 451 452 private: 453 HTMLEditor* mHTMLEditor; 454 bool mIsCSSPrefChecked; 455 }; 456 457 #define NS_EDITOR_INDENT_INCREMENT_IN 0.4134f 458 #define NS_EDITOR_INDENT_INCREMENT_CM 1.05f 459 #define NS_EDITOR_INDENT_INCREMENT_MM 10.5f 460 #define NS_EDITOR_INDENT_INCREMENT_PT 29.76f 461 #define NS_EDITOR_INDENT_INCREMENT_PC 2.48f 462 #define NS_EDITOR_INDENT_INCREMENT_EM 3 463 #define NS_EDITOR_INDENT_INCREMENT_EX 6 464 #define NS_EDITOR_INDENT_INCREMENT_PX 40 465 #define NS_EDITOR_INDENT_INCREMENT_PERCENT 4 466 467 } // namespace mozilla 468 469 #endif // #ifndef mozilla_CSSEditUtils_h 470