editor/libeditor/html/nsHTMLCSSUtils.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "ChangeCSSInlineStyleTxn.h"
michael@0 7 #include "EditTxn.h"
michael@0 8 #include "mozilla/Assertions.h"
michael@0 9 #include "mozilla/Preferences.h"
michael@0 10 #include "mozilla/css/Declaration.h"
michael@0 11 #include "mozilla/css/StyleRule.h"
michael@0 12 #include "mozilla/dom/Element.h"
michael@0 13 #include "mozilla/mozalloc.h"
michael@0 14 #include "nsAString.h"
michael@0 15 #include "nsAutoPtr.h"
michael@0 16 #include "nsCOMPtr.h"
michael@0 17 #include "nsColor.h"
michael@0 18 #include "nsComputedDOMStyle.h"
michael@0 19 #include "nsDebug.h"
michael@0 20 #include "nsDependentSubstring.h"
michael@0 21 #include "nsEditProperty.h"
michael@0 22 #include "nsError.h"
michael@0 23 #include "nsGkAtoms.h"
michael@0 24 #include "nsHTMLCSSUtils.h"
michael@0 25 #include "nsHTMLEditor.h"
michael@0 26 #include "nsIAtom.h"
michael@0 27 #include "nsIContent.h"
michael@0 28 #include "nsIDOMCSSStyleDeclaration.h"
michael@0 29 #include "nsIDOMElement.h"
michael@0 30 #include "nsIDOMElementCSSInlineStyle.h"
michael@0 31 #include "nsIDOMNode.h"
michael@0 32 #include "nsIDOMWindow.h"
michael@0 33 #include "nsIDocument.h"
michael@0 34 #include "nsIEditor.h"
michael@0 35 #include "nsINode.h"
michael@0 36 #include "nsISupportsImpl.h"
michael@0 37 #include "nsISupportsUtils.h"
michael@0 38 #include "nsLiteralString.h"
michael@0 39 #include "nsPIDOMWindow.h"
michael@0 40 #include "nsReadableUtils.h"
michael@0 41 #include "nsString.h"
michael@0 42 #include "nsStringFwd.h"
michael@0 43 #include "nsStringIterator.h"
michael@0 44 #include "nsSubstringTuple.h"
michael@0 45 #include "nsUnicharUtils.h"
michael@0 46
michael@0 47 using namespace mozilla;
michael@0 48
michael@0 49 static
michael@0 50 void ProcessBValue(const nsAString * aInputString, nsAString & aOutputString,
michael@0 51 const char * aDefaultValueString,
michael@0 52 const char * aPrependString, const char* aAppendString)
michael@0 53 {
michael@0 54 if (aInputString && aInputString->EqualsLiteral("-moz-editor-invert-value")) {
michael@0 55 aOutputString.AssignLiteral("normal");
michael@0 56 }
michael@0 57 else {
michael@0 58 aOutputString.AssignLiteral("bold");
michael@0 59 }
michael@0 60 }
michael@0 61
michael@0 62 static
michael@0 63 void ProcessDefaultValue(const nsAString * aInputString, nsAString & aOutputString,
michael@0 64 const char * aDefaultValueString,
michael@0 65 const char * aPrependString, const char* aAppendString)
michael@0 66 {
michael@0 67 CopyASCIItoUTF16(aDefaultValueString, aOutputString);
michael@0 68 }
michael@0 69
michael@0 70 static
michael@0 71 void ProcessSameValue(const nsAString * aInputString, nsAString & aOutputString,
michael@0 72 const char * aDefaultValueString,
michael@0 73 const char * aPrependString, const char* aAppendString)
michael@0 74 {
michael@0 75 if (aInputString) {
michael@0 76 aOutputString.Assign(*aInputString);
michael@0 77 }
michael@0 78 else
michael@0 79 aOutputString.Truncate();
michael@0 80 }
michael@0 81
michael@0 82 static
michael@0 83 void ProcessExtendedValue(const nsAString * aInputString, nsAString & aOutputString,
michael@0 84 const char * aDefaultValueString,
michael@0 85 const char * aPrependString, const char* aAppendString)
michael@0 86 {
michael@0 87 aOutputString.Truncate();
michael@0 88 if (aInputString) {
michael@0 89 if (aPrependString) {
michael@0 90 AppendASCIItoUTF16(aPrependString, aOutputString);
michael@0 91 }
michael@0 92 aOutputString.Append(*aInputString);
michael@0 93 if (aAppendString) {
michael@0 94 AppendASCIItoUTF16(aAppendString, aOutputString);
michael@0 95 }
michael@0 96 }
michael@0 97 }
michael@0 98
michael@0 99 static
michael@0 100 void ProcessLengthValue(const nsAString * aInputString, nsAString & aOutputString,
michael@0 101 const char * aDefaultValueString,
michael@0 102 const char * aPrependString, const char* aAppendString)
michael@0 103 {
michael@0 104 aOutputString.Truncate();
michael@0 105 if (aInputString) {
michael@0 106 aOutputString.Append(*aInputString);
michael@0 107 if (-1 == aOutputString.FindChar(char16_t('%'))) {
michael@0 108 aOutputString.AppendLiteral("px");
michael@0 109 }
michael@0 110 }
michael@0 111 }
michael@0 112
michael@0 113 static
michael@0 114 void ProcessListStyleTypeValue(const nsAString * aInputString, nsAString & aOutputString,
michael@0 115 const char * aDefaultValueString,
michael@0 116 const char * aPrependString, const char* aAppendString)
michael@0 117 {
michael@0 118 aOutputString.Truncate();
michael@0 119 if (aInputString) {
michael@0 120 if (aInputString->EqualsLiteral("1")) {
michael@0 121 aOutputString.AppendLiteral("decimal");
michael@0 122 }
michael@0 123 else if (aInputString->EqualsLiteral("a")) {
michael@0 124 aOutputString.AppendLiteral("lower-alpha");
michael@0 125 }
michael@0 126 else if (aInputString->EqualsLiteral("A")) {
michael@0 127 aOutputString.AppendLiteral("upper-alpha");
michael@0 128 }
michael@0 129 else if (aInputString->EqualsLiteral("i")) {
michael@0 130 aOutputString.AppendLiteral("lower-roman");
michael@0 131 }
michael@0 132 else if (aInputString->EqualsLiteral("I")) {
michael@0 133 aOutputString.AppendLiteral("upper-roman");
michael@0 134 }
michael@0 135 else if (aInputString->EqualsLiteral("square")
michael@0 136 || aInputString->EqualsLiteral("circle")
michael@0 137 || aInputString->EqualsLiteral("disc")) {
michael@0 138 aOutputString.Append(*aInputString);
michael@0 139 }
michael@0 140 }
michael@0 141 }
michael@0 142
michael@0 143 static
michael@0 144 void ProcessMarginLeftValue(const nsAString * aInputString, nsAString & aOutputString,
michael@0 145 const char * aDefaultValueString,
michael@0 146 const char * aPrependString, const char* aAppendString)
michael@0 147 {
michael@0 148 aOutputString.Truncate();
michael@0 149 if (aInputString) {
michael@0 150 if (aInputString->EqualsLiteral("center") ||
michael@0 151 aInputString->EqualsLiteral("-moz-center")) {
michael@0 152 aOutputString.AppendLiteral("auto");
michael@0 153 }
michael@0 154 else if (aInputString->EqualsLiteral("right") ||
michael@0 155 aInputString->EqualsLiteral("-moz-right")) {
michael@0 156 aOutputString.AppendLiteral("auto");
michael@0 157 }
michael@0 158 else {
michael@0 159 aOutputString.AppendLiteral("0px");
michael@0 160 }
michael@0 161 }
michael@0 162 }
michael@0 163
michael@0 164 static
michael@0 165 void ProcessMarginRightValue(const nsAString * aInputString, nsAString & aOutputString,
michael@0 166 const char * aDefaultValueString,
michael@0 167 const char * aPrependString, const char* aAppendString)
michael@0 168 {
michael@0 169 aOutputString.Truncate();
michael@0 170 if (aInputString) {
michael@0 171 if (aInputString->EqualsLiteral("center") ||
michael@0 172 aInputString->EqualsLiteral("-moz-center")) {
michael@0 173 aOutputString.AppendLiteral("auto");
michael@0 174 }
michael@0 175 else if (aInputString->EqualsLiteral("left") ||
michael@0 176 aInputString->EqualsLiteral("-moz-left")) {
michael@0 177 aOutputString.AppendLiteral("auto");
michael@0 178 }
michael@0 179 else {
michael@0 180 aOutputString.AppendLiteral("0px");
michael@0 181 }
michael@0 182 }
michael@0 183 }
michael@0 184
michael@0 185 const nsHTMLCSSUtils::CSSEquivTable boldEquivTable[] = {
michael@0 186 { nsHTMLCSSUtils::eCSSEditableProperty_font_weight, ProcessBValue, nullptr, nullptr, nullptr, true, false },
michael@0 187 { nsHTMLCSSUtils::eCSSEditableProperty_NONE, 0 }
michael@0 188 };
michael@0 189
michael@0 190 const nsHTMLCSSUtils::CSSEquivTable italicEquivTable[] = {
michael@0 191 { nsHTMLCSSUtils::eCSSEditableProperty_font_style, ProcessDefaultValue, "italic", nullptr, nullptr, true, false },
michael@0 192 { nsHTMLCSSUtils::eCSSEditableProperty_NONE, 0 }
michael@0 193 };
michael@0 194
michael@0 195 const nsHTMLCSSUtils::CSSEquivTable underlineEquivTable[] = {
michael@0 196 { nsHTMLCSSUtils::eCSSEditableProperty_text_decoration, ProcessDefaultValue, "underline", nullptr, nullptr, true, false },
michael@0 197 { nsHTMLCSSUtils::eCSSEditableProperty_NONE, 0 }
michael@0 198 };
michael@0 199
michael@0 200 const nsHTMLCSSUtils::CSSEquivTable strikeEquivTable[] = {
michael@0 201 { nsHTMLCSSUtils::eCSSEditableProperty_text_decoration, ProcessDefaultValue, "line-through", nullptr, nullptr, true, false },
michael@0 202 { nsHTMLCSSUtils::eCSSEditableProperty_NONE, 0 }
michael@0 203 };
michael@0 204
michael@0 205 const nsHTMLCSSUtils::CSSEquivTable ttEquivTable[] = {
michael@0 206 { nsHTMLCSSUtils::eCSSEditableProperty_font_family, ProcessDefaultValue, "monospace", nullptr, nullptr, true, false },
michael@0 207 { nsHTMLCSSUtils::eCSSEditableProperty_NONE, 0 }
michael@0 208 };
michael@0 209
michael@0 210 const nsHTMLCSSUtils::CSSEquivTable fontColorEquivTable[] = {
michael@0 211 { nsHTMLCSSUtils::eCSSEditableProperty_color, ProcessSameValue, nullptr, nullptr, nullptr, true, false },
michael@0 212 { nsHTMLCSSUtils::eCSSEditableProperty_NONE, 0 }
michael@0 213 };
michael@0 214
michael@0 215 const nsHTMLCSSUtils::CSSEquivTable fontFaceEquivTable[] = {
michael@0 216 { nsHTMLCSSUtils::eCSSEditableProperty_font_family, ProcessSameValue, nullptr, nullptr, nullptr, true, false },
michael@0 217 { nsHTMLCSSUtils::eCSSEditableProperty_NONE, 0 }
michael@0 218 };
michael@0 219
michael@0 220 const nsHTMLCSSUtils::CSSEquivTable bgcolorEquivTable[] = {
michael@0 221 { nsHTMLCSSUtils::eCSSEditableProperty_background_color, ProcessSameValue, nullptr, nullptr, nullptr, true, false },
michael@0 222 { nsHTMLCSSUtils::eCSSEditableProperty_NONE, 0 }
michael@0 223 };
michael@0 224
michael@0 225 const nsHTMLCSSUtils::CSSEquivTable backgroundImageEquivTable[] = {
michael@0 226 { nsHTMLCSSUtils::eCSSEditableProperty_background_image, ProcessExtendedValue, nullptr, "url(", ")", true, true },
michael@0 227 { nsHTMLCSSUtils::eCSSEditableProperty_NONE, 0 }
michael@0 228 };
michael@0 229
michael@0 230 const nsHTMLCSSUtils::CSSEquivTable textColorEquivTable[] = {
michael@0 231 { nsHTMLCSSUtils::eCSSEditableProperty_color, ProcessSameValue, nullptr, nullptr, nullptr, true, false },
michael@0 232 { nsHTMLCSSUtils::eCSSEditableProperty_NONE, 0 }
michael@0 233 };
michael@0 234
michael@0 235 const nsHTMLCSSUtils::CSSEquivTable borderEquivTable[] = {
michael@0 236 { nsHTMLCSSUtils::eCSSEditableProperty_border, ProcessExtendedValue, nullptr, nullptr, "px solid", true, false },
michael@0 237 { nsHTMLCSSUtils::eCSSEditableProperty_NONE, 0 }
michael@0 238 };
michael@0 239
michael@0 240 const nsHTMLCSSUtils::CSSEquivTable textAlignEquivTable[] = {
michael@0 241 { nsHTMLCSSUtils::eCSSEditableProperty_text_align, ProcessSameValue, nullptr, nullptr, nullptr, true, false },
michael@0 242 { nsHTMLCSSUtils::eCSSEditableProperty_NONE, 0 }
michael@0 243 };
michael@0 244
michael@0 245 const nsHTMLCSSUtils::CSSEquivTable captionAlignEquivTable[] = {
michael@0 246 { nsHTMLCSSUtils::eCSSEditableProperty_caption_side, ProcessSameValue, nullptr, nullptr, nullptr, true, false },
michael@0 247 { nsHTMLCSSUtils::eCSSEditableProperty_NONE, 0 }
michael@0 248 };
michael@0 249
michael@0 250 const nsHTMLCSSUtils::CSSEquivTable verticalAlignEquivTable[] = {
michael@0 251 { nsHTMLCSSUtils::eCSSEditableProperty_vertical_align, ProcessSameValue, nullptr, nullptr, nullptr, true, false },
michael@0 252 { nsHTMLCSSUtils::eCSSEditableProperty_NONE, 0 }
michael@0 253 };
michael@0 254
michael@0 255 const nsHTMLCSSUtils::CSSEquivTable nowrapEquivTable[] = {
michael@0 256 { nsHTMLCSSUtils::eCSSEditableProperty_whitespace, ProcessDefaultValue, "nowrap", nullptr, nullptr, true, false },
michael@0 257 { nsHTMLCSSUtils::eCSSEditableProperty_NONE, 0 }
michael@0 258 };
michael@0 259
michael@0 260 const nsHTMLCSSUtils::CSSEquivTable widthEquivTable[] = {
michael@0 261 { nsHTMLCSSUtils::eCSSEditableProperty_width, ProcessLengthValue, nullptr, nullptr, nullptr, true, false },
michael@0 262 { nsHTMLCSSUtils::eCSSEditableProperty_NONE, 0 }
michael@0 263 };
michael@0 264
michael@0 265 const nsHTMLCSSUtils::CSSEquivTable heightEquivTable[] = {
michael@0 266 { nsHTMLCSSUtils::eCSSEditableProperty_height, ProcessLengthValue, nullptr, nullptr, nullptr, true, false },
michael@0 267 { nsHTMLCSSUtils::eCSSEditableProperty_NONE, 0 }
michael@0 268 };
michael@0 269
michael@0 270 const nsHTMLCSSUtils::CSSEquivTable listStyleTypeEquivTable[] = {
michael@0 271 { nsHTMLCSSUtils::eCSSEditableProperty_list_style_type, ProcessListStyleTypeValue, nullptr, nullptr, nullptr, true, true },
michael@0 272 { nsHTMLCSSUtils::eCSSEditableProperty_NONE, 0 }
michael@0 273 };
michael@0 274
michael@0 275 const nsHTMLCSSUtils::CSSEquivTable tableAlignEquivTable[] = {
michael@0 276 { nsHTMLCSSUtils::eCSSEditableProperty_text_align, ProcessDefaultValue, "left", nullptr, nullptr, false, false },
michael@0 277 { nsHTMLCSSUtils::eCSSEditableProperty_margin_left, ProcessMarginLeftValue, nullptr, nullptr, nullptr, true, false },
michael@0 278 { nsHTMLCSSUtils::eCSSEditableProperty_margin_right, ProcessMarginRightValue, nullptr, nullptr, nullptr, true, false },
michael@0 279 { nsHTMLCSSUtils::eCSSEditableProperty_NONE, 0 }
michael@0 280 };
michael@0 281
michael@0 282 const nsHTMLCSSUtils::CSSEquivTable hrAlignEquivTable[] = {
michael@0 283 { nsHTMLCSSUtils::eCSSEditableProperty_margin_left, ProcessMarginLeftValue, nullptr, nullptr, nullptr, true, false },
michael@0 284 { nsHTMLCSSUtils::eCSSEditableProperty_margin_right, ProcessMarginRightValue, nullptr, nullptr, nullptr, true, false },
michael@0 285 { nsHTMLCSSUtils::eCSSEditableProperty_NONE, 0 }
michael@0 286 };
michael@0 287
michael@0 288 nsHTMLCSSUtils::nsHTMLCSSUtils(nsHTMLEditor* aEditor)
michael@0 289 : mHTMLEditor(aEditor)
michael@0 290 , mIsCSSPrefChecked(true)
michael@0 291 {
michael@0 292 // let's retrieve the value of the "CSS editing" pref
michael@0 293 mIsCSSPrefChecked = Preferences::GetBool("editor.use_css", mIsCSSPrefChecked);
michael@0 294 }
michael@0 295
michael@0 296 nsHTMLCSSUtils::~nsHTMLCSSUtils()
michael@0 297 {
michael@0 298 }
michael@0 299
michael@0 300 // Answers true if we have some CSS equivalence for the HTML style defined
michael@0 301 // by aProperty and/or aAttribute for the node aNode
michael@0 302 bool
michael@0 303 nsHTMLCSSUtils::IsCSSEditableProperty(nsIDOMNode* aNode,
michael@0 304 nsIAtom* aProperty,
michael@0 305 const nsAString* aAttribute)
michael@0 306 {
michael@0 307 NS_ASSERTION(aNode, "Shouldn't you pass aNode? - Bug 214025");
michael@0 308
michael@0 309 nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
michael@0 310 NS_ENSURE_TRUE(content, false);
michael@0 311 return IsCSSEditableProperty(content, aProperty, aAttribute);
michael@0 312 }
michael@0 313
michael@0 314 bool
michael@0 315 nsHTMLCSSUtils::IsCSSEditableProperty(nsIContent* aNode,
michael@0 316 nsIAtom* aProperty,
michael@0 317 const nsAString* aAttribute)
michael@0 318 {
michael@0 319 MOZ_ASSERT(aNode);
michael@0 320
michael@0 321 nsIContent* content = aNode;
michael@0 322 // we need an element node here
michael@0 323 if (content->NodeType() == nsIDOMNode::TEXT_NODE) {
michael@0 324 content = content->GetParent();
michael@0 325 NS_ENSURE_TRUE(content, false);
michael@0 326 }
michael@0 327
michael@0 328 nsIAtom *tagName = content->Tag();
michael@0 329 // brade: shouldn't some of the above go below the next block?
michael@0 330
michael@0 331 // html inline styles B I TT U STRIKE and COLOR/FACE on FONT
michael@0 332 if (nsEditProperty::b == aProperty
michael@0 333 || nsEditProperty::i == aProperty
michael@0 334 || nsEditProperty::tt == aProperty
michael@0 335 || nsEditProperty::u == aProperty
michael@0 336 || nsEditProperty::strike == aProperty
michael@0 337 || ((nsEditProperty::font == aProperty) && aAttribute &&
michael@0 338 (aAttribute->EqualsLiteral("color") ||
michael@0 339 aAttribute->EqualsLiteral("face")))) {
michael@0 340 return true;
michael@0 341 }
michael@0 342
michael@0 343 // ALIGN attribute on elements supporting it
michael@0 344 if (aAttribute && (aAttribute->EqualsLiteral("align")) &&
michael@0 345 (nsEditProperty::div == tagName
michael@0 346 || nsEditProperty::p == tagName
michael@0 347 || nsEditProperty::h1 == tagName
michael@0 348 || nsEditProperty::h2 == tagName
michael@0 349 || nsEditProperty::h3 == tagName
michael@0 350 || nsEditProperty::h4 == tagName
michael@0 351 || nsEditProperty::h5 == tagName
michael@0 352 || nsEditProperty::h6 == tagName
michael@0 353 || nsEditProperty::td == tagName
michael@0 354 || nsEditProperty::th == tagName
michael@0 355 || nsEditProperty::table == tagName
michael@0 356 || nsEditProperty::hr == tagName
michael@0 357 // brade: for the above, why not use nsHTMLEditUtils::SupportsAlignAttr
michael@0 358 // brade: but it also checks for tbody, tfoot, thead
michael@0 359 // Let's add the following elements here even if ALIGN has not
michael@0 360 // the same meaning for them
michael@0 361 || nsEditProperty::legend == tagName
michael@0 362 || nsEditProperty::caption == tagName)) {
michael@0 363 return true;
michael@0 364 }
michael@0 365
michael@0 366 if (aAttribute && (aAttribute->EqualsLiteral("valign")) &&
michael@0 367 (nsEditProperty::col == tagName
michael@0 368 || nsEditProperty::colgroup == tagName
michael@0 369 || nsEditProperty::tbody == tagName
michael@0 370 || nsEditProperty::td == tagName
michael@0 371 || nsEditProperty::th == tagName
michael@0 372 || nsEditProperty::tfoot == tagName
michael@0 373 || nsEditProperty::thead == tagName
michael@0 374 || nsEditProperty::tr == tagName)) {
michael@0 375 return true;
michael@0 376 }
michael@0 377
michael@0 378 // attributes TEXT, BACKGROUND and BGCOLOR on BODY
michael@0 379 if (aAttribute && (nsEditProperty::body == tagName) &&
michael@0 380 (aAttribute->EqualsLiteral("text")
michael@0 381 || aAttribute->EqualsLiteral("background")
michael@0 382 || aAttribute->EqualsLiteral("bgcolor"))) {
michael@0 383 return true;
michael@0 384 }
michael@0 385
michael@0 386 // attribute BGCOLOR on other elements
michael@0 387 if (aAttribute && aAttribute->EqualsLiteral("bgcolor")) {
michael@0 388 return true;
michael@0 389 }
michael@0 390
michael@0 391 // attributes HEIGHT, WIDTH and NOWRAP on TD and TH
michael@0 392 if (aAttribute && ((nsEditProperty::td == tagName)
michael@0 393 || (nsEditProperty::th == tagName)) &&
michael@0 394 (aAttribute->EqualsLiteral("height")
michael@0 395 || aAttribute->EqualsLiteral("width")
michael@0 396 || aAttribute->EqualsLiteral("nowrap"))) {
michael@0 397 return true;
michael@0 398 }
michael@0 399
michael@0 400 // attributes HEIGHT and WIDTH on TABLE
michael@0 401 if (aAttribute && (nsEditProperty::table == tagName) &&
michael@0 402 (aAttribute->EqualsLiteral("height")
michael@0 403 || aAttribute->EqualsLiteral("width"))) {
michael@0 404 return true;
michael@0 405 }
michael@0 406
michael@0 407 // attributes SIZE and WIDTH on HR
michael@0 408 if (aAttribute && (nsEditProperty::hr == tagName) &&
michael@0 409 (aAttribute->EqualsLiteral("size")
michael@0 410 || aAttribute->EqualsLiteral("width"))) {
michael@0 411 return true;
michael@0 412 }
michael@0 413
michael@0 414 // attribute TYPE on OL UL LI
michael@0 415 if (aAttribute && (nsEditProperty::ol == tagName
michael@0 416 || nsEditProperty::ul == tagName
michael@0 417 || nsEditProperty::li == tagName) &&
michael@0 418 aAttribute->EqualsLiteral("type")) {
michael@0 419 return true;
michael@0 420 }
michael@0 421
michael@0 422 if (aAttribute && nsEditProperty::img == tagName &&
michael@0 423 (aAttribute->EqualsLiteral("border")
michael@0 424 || aAttribute->EqualsLiteral("width")
michael@0 425 || aAttribute->EqualsLiteral("height"))) {
michael@0 426 return true;
michael@0 427 }
michael@0 428
michael@0 429 // other elements that we can align using CSS even if they
michael@0 430 // can't carry the html ALIGN attribute
michael@0 431 if (aAttribute && aAttribute->EqualsLiteral("align") &&
michael@0 432 (nsEditProperty::ul == tagName
michael@0 433 || nsEditProperty::ol == tagName
michael@0 434 || nsEditProperty::dl == tagName
michael@0 435 || nsEditProperty::li == tagName
michael@0 436 || nsEditProperty::dd == tagName
michael@0 437 || nsEditProperty::dt == tagName
michael@0 438 || nsEditProperty::address == tagName
michael@0 439 || nsEditProperty::pre == tagName
michael@0 440 || nsEditProperty::ul == tagName)) {
michael@0 441 return true;
michael@0 442 }
michael@0 443
michael@0 444 return false;
michael@0 445 }
michael@0 446
michael@0 447 // the lowest level above the transaction; adds the css declaration "aProperty : aValue" to
michael@0 448 // the inline styles carried by aElement
michael@0 449 nsresult
michael@0 450 nsHTMLCSSUtils::SetCSSProperty(nsIDOMElement *aElement, nsIAtom * aProperty, const nsAString & aValue,
michael@0 451 bool aSuppressTransaction)
michael@0 452 {
michael@0 453 nsRefPtr<ChangeCSSInlineStyleTxn> txn;
michael@0 454 nsresult result = CreateCSSPropertyTxn(aElement, aProperty, aValue,
michael@0 455 getter_AddRefs(txn), false);
michael@0 456 if (NS_SUCCEEDED(result)) {
michael@0 457 if (aSuppressTransaction) {
michael@0 458 result = txn->DoTransaction();
michael@0 459 }
michael@0 460 else {
michael@0 461 result = mHTMLEditor->DoTransaction(txn);
michael@0 462 }
michael@0 463 }
michael@0 464 return result;
michael@0 465 }
michael@0 466
michael@0 467 nsresult
michael@0 468 nsHTMLCSSUtils::SetCSSPropertyPixels(nsIDOMElement *aElement,
michael@0 469 nsIAtom *aProperty,
michael@0 470 int32_t aIntValue,
michael@0 471 bool aSuppressTransaction)
michael@0 472 {
michael@0 473 nsAutoString s;
michael@0 474 s.AppendInt(aIntValue);
michael@0 475 return SetCSSProperty(aElement, aProperty, s + NS_LITERAL_STRING("px"),
michael@0 476 aSuppressTransaction);
michael@0 477 }
michael@0 478
michael@0 479 // the lowest level above the transaction; removes the value aValue from the list of values
michael@0 480 // specified for the CSS property aProperty, or totally remove the declaration if this
michael@0 481 // property accepts only one value
michael@0 482 nsresult
michael@0 483 nsHTMLCSSUtils::RemoveCSSProperty(nsIDOMElement *aElement, nsIAtom * aProperty, const nsAString & aValue,
michael@0 484 bool aSuppressTransaction)
michael@0 485 {
michael@0 486 nsRefPtr<ChangeCSSInlineStyleTxn> txn;
michael@0 487 nsresult result = CreateCSSPropertyTxn(aElement, aProperty, aValue,
michael@0 488 getter_AddRefs(txn), true);
michael@0 489 if (NS_SUCCEEDED(result)) {
michael@0 490 if (aSuppressTransaction) {
michael@0 491 result = txn->DoTransaction();
michael@0 492 }
michael@0 493 else {
michael@0 494 result = mHTMLEditor->DoTransaction(txn);
michael@0 495 }
michael@0 496 }
michael@0 497 return result;
michael@0 498 }
michael@0 499
michael@0 500 nsresult
michael@0 501 nsHTMLCSSUtils::CreateCSSPropertyTxn(nsIDOMElement *aElement,
michael@0 502 nsIAtom * aAttribute,
michael@0 503 const nsAString& aValue,
michael@0 504 ChangeCSSInlineStyleTxn ** aTxn,
michael@0 505 bool aRemoveProperty)
michael@0 506 {
michael@0 507 NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER);
michael@0 508
michael@0 509 *aTxn = new ChangeCSSInlineStyleTxn();
michael@0 510 NS_ENSURE_TRUE(*aTxn, NS_ERROR_OUT_OF_MEMORY);
michael@0 511 NS_ADDREF(*aTxn);
michael@0 512 return (*aTxn)->Init(mHTMLEditor, aElement, aAttribute, aValue, aRemoveProperty);
michael@0 513 }
michael@0 514
michael@0 515 nsresult
michael@0 516 nsHTMLCSSUtils::GetSpecifiedProperty(nsIDOMNode *aNode, nsIAtom *aProperty,
michael@0 517 nsAString & aValue)
michael@0 518 {
michael@0 519 return GetCSSInlinePropertyBase(aNode, aProperty, aValue, eSpecified);
michael@0 520 }
michael@0 521
michael@0 522 nsresult
michael@0 523 nsHTMLCSSUtils::GetComputedProperty(nsIDOMNode *aNode, nsIAtom *aProperty,
michael@0 524 nsAString & aValue)
michael@0 525 {
michael@0 526 return GetCSSInlinePropertyBase(aNode, aProperty, aValue, eComputed);
michael@0 527 }
michael@0 528
michael@0 529 nsresult
michael@0 530 nsHTMLCSSUtils::GetCSSInlinePropertyBase(nsIDOMNode* aNode, nsIAtom* aProperty,
michael@0 531 nsAString& aValue,
michael@0 532 StyleType aStyleType)
michael@0 533 {
michael@0 534 nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
michael@0 535 return GetCSSInlinePropertyBase(node, aProperty, aValue, aStyleType);
michael@0 536 }
michael@0 537
michael@0 538 nsresult
michael@0 539 nsHTMLCSSUtils::GetCSSInlinePropertyBase(nsINode* aNode, nsIAtom* aProperty,
michael@0 540 nsAString& aValue,
michael@0 541 StyleType aStyleType)
michael@0 542 {
michael@0 543 MOZ_ASSERT(aNode && aProperty);
michael@0 544 aValue.Truncate();
michael@0 545
michael@0 546 nsCOMPtr<dom::Element> element = GetElementContainerOrSelf(aNode);
michael@0 547 NS_ENSURE_TRUE(element, NS_ERROR_NULL_POINTER);
michael@0 548
michael@0 549 if (aStyleType == eComputed) {
michael@0 550 // Get the all the computed css styles attached to the element node
michael@0 551 nsRefPtr<nsComputedDOMStyle> cssDecl = GetComputedStyle(element);
michael@0 552 NS_ENSURE_STATE(cssDecl);
michael@0 553
michael@0 554 // from these declarations, get the one we want and that one only
michael@0 555 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
michael@0 556 cssDecl->GetPropertyValue(nsDependentAtomString(aProperty), aValue)));
michael@0 557
michael@0 558 return NS_OK;
michael@0 559 }
michael@0 560
michael@0 561 MOZ_ASSERT(aStyleType == eSpecified);
michael@0 562 nsRefPtr<css::StyleRule> rule = element->GetInlineStyleRule();
michael@0 563 if (!rule) {
michael@0 564 return NS_OK;
michael@0 565 }
michael@0 566 nsCSSProperty prop =
michael@0 567 nsCSSProps::LookupProperty(nsDependentAtomString(aProperty),
michael@0 568 nsCSSProps::eEnabledForAllContent);
michael@0 569 MOZ_ASSERT(prop != eCSSProperty_UNKNOWN);
michael@0 570 rule->GetDeclaration()->GetValue(prop, aValue);
michael@0 571
michael@0 572 return NS_OK;
michael@0 573 }
michael@0 574
michael@0 575 already_AddRefed<nsComputedDOMStyle>
michael@0 576 nsHTMLCSSUtils::GetComputedStyle(nsIDOMElement* aElement)
michael@0 577 {
michael@0 578 nsCOMPtr<dom::Element> element = do_QueryInterface(aElement);
michael@0 579 return GetComputedStyle(element);
michael@0 580 }
michael@0 581
michael@0 582 already_AddRefed<nsComputedDOMStyle>
michael@0 583 nsHTMLCSSUtils::GetComputedStyle(dom::Element* aElement)
michael@0 584 {
michael@0 585 MOZ_ASSERT(aElement);
michael@0 586
michael@0 587 nsIDocument* doc = aElement->GetCurrentDoc();
michael@0 588 NS_ENSURE_TRUE(doc, nullptr);
michael@0 589
michael@0 590 nsIPresShell* presShell = doc->GetShell();
michael@0 591 NS_ENSURE_TRUE(presShell, nullptr);
michael@0 592
michael@0 593 nsRefPtr<nsComputedDOMStyle> style =
michael@0 594 NS_NewComputedDOMStyle(aElement, EmptyString(), presShell);
michael@0 595
michael@0 596 return style.forget();
michael@0 597 }
michael@0 598
michael@0 599 // remove the CSS style "aProperty : aPropertyValue" and possibly remove the whole node
michael@0 600 // if it is a span and if its only attribute is _moz_dirty
michael@0 601 nsresult
michael@0 602 nsHTMLCSSUtils::RemoveCSSInlineStyle(nsIDOMNode *aNode, nsIAtom *aProperty, const nsAString & aPropertyValue)
michael@0 603 {
michael@0 604 nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(aNode);
michael@0 605
michael@0 606 // remove the property from the style attribute
michael@0 607 nsresult res = RemoveCSSProperty(elem, aProperty, aPropertyValue, false);
michael@0 608 NS_ENSURE_SUCCESS(res, res);
michael@0 609
michael@0 610 nsCOMPtr<dom::Element> element = do_QueryInterface(aNode);
michael@0 611 if (!element || !element->IsHTML(nsGkAtoms::span) ||
michael@0 612 nsHTMLEditor::HasAttributes(element)) {
michael@0 613 return NS_OK;
michael@0 614 }
michael@0 615
michael@0 616 return mHTMLEditor->RemoveContainer(aNode);
michael@0 617 }
michael@0 618
michael@0 619 // Answers true is the property can be removed by setting a "none" CSS value
michael@0 620 // on a node
michael@0 621 bool
michael@0 622 nsHTMLCSSUtils::IsCSSInvertable(nsIAtom *aProperty, const nsAString *aAttribute)
michael@0 623 {
michael@0 624 return bool(nsEditProperty::b == aProperty);
michael@0 625 }
michael@0 626
michael@0 627 // Get the default browser background color if we need it for GetCSSBackgroundColorState
michael@0 628 void
michael@0 629 nsHTMLCSSUtils::GetDefaultBackgroundColor(nsAString & aColor)
michael@0 630 {
michael@0 631 if (Preferences::GetBool("editor.use_custom_colors", false)) {
michael@0 632 nsresult rv = Preferences::GetString("editor.background_color", &aColor);
michael@0 633 // XXX Why don't you validate the pref value?
michael@0 634 if (NS_FAILED(rv)) {
michael@0 635 NS_WARNING("failed to get editor.background_color");
michael@0 636 aColor.AssignLiteral("#ffffff"); // Default to white
michael@0 637 }
michael@0 638 return;
michael@0 639 }
michael@0 640
michael@0 641 if (Preferences::GetBool("browser.display.use_system_colors", false)) {
michael@0 642 return;
michael@0 643 }
michael@0 644
michael@0 645 nsresult rv =
michael@0 646 Preferences::GetString("browser.display.background_color", &aColor);
michael@0 647 // XXX Why don't you validate the pref value?
michael@0 648 if (NS_FAILED(rv)) {
michael@0 649 NS_WARNING("failed to get browser.display.background_color");
michael@0 650 aColor.AssignLiteral("#ffffff"); // Default to white
michael@0 651 }
michael@0 652 }
michael@0 653
michael@0 654 // Get the default length unit used for CSS Indent/Outdent
michael@0 655 void
michael@0 656 nsHTMLCSSUtils::GetDefaultLengthUnit(nsAString & aLengthUnit)
michael@0 657 {
michael@0 658 nsresult rv =
michael@0 659 Preferences::GetString("editor.css.default_length_unit", &aLengthUnit);
michael@0 660 // XXX Why don't you validate the pref value?
michael@0 661 if (NS_FAILED(rv)) {
michael@0 662 aLengthUnit.AssignLiteral("px");
michael@0 663 }
michael@0 664 }
michael@0 665
michael@0 666 // Unfortunately, CSSStyleDeclaration::GetPropertyCSSValue is not yet implemented...
michael@0 667 // We need then a way to determine the number part and the unit from aString, aString
michael@0 668 // being the result of a GetPropertyValue query...
michael@0 669 void
michael@0 670 nsHTMLCSSUtils::ParseLength(const nsAString & aString, float * aValue, nsIAtom ** aUnit)
michael@0 671 {
michael@0 672 nsAString::const_iterator iter;
michael@0 673 aString.BeginReading(iter);
michael@0 674
michael@0 675 float a = 10.0f , b = 1.0f, value = 0;
michael@0 676 int8_t sign = 1;
michael@0 677 int32_t i = 0, j = aString.Length();
michael@0 678 char16_t c;
michael@0 679 bool floatingPointFound = false;
michael@0 680 c = *iter;
michael@0 681 if (char16_t('-') == c) { sign = -1; iter++; i++; }
michael@0 682 else if (char16_t('+') == c) { iter++; i++; }
michael@0 683 while (i < j) {
michael@0 684 c = *iter;
michael@0 685 if ((char16_t('0') == c) ||
michael@0 686 (char16_t('1') == c) ||
michael@0 687 (char16_t('2') == c) ||
michael@0 688 (char16_t('3') == c) ||
michael@0 689 (char16_t('4') == c) ||
michael@0 690 (char16_t('5') == c) ||
michael@0 691 (char16_t('6') == c) ||
michael@0 692 (char16_t('7') == c) ||
michael@0 693 (char16_t('8') == c) ||
michael@0 694 (char16_t('9') == c)) {
michael@0 695 value = (value * a) + (b * (c - char16_t('0')));
michael@0 696 b = b / 10 * a;
michael@0 697 }
michael@0 698 else if (!floatingPointFound && (char16_t('.') == c)) {
michael@0 699 floatingPointFound = true;
michael@0 700 a = 1.0f; b = 0.1f;
michael@0 701 }
michael@0 702 else break;
michael@0 703 iter++;
michael@0 704 i++;
michael@0 705 }
michael@0 706 *aValue = value * sign;
michael@0 707 *aUnit = NS_NewAtom(StringTail(aString, j-i)).take();
michael@0 708 }
michael@0 709
michael@0 710 void
michael@0 711 nsHTMLCSSUtils::GetCSSPropertyAtom(nsCSSEditableProperty aProperty, nsIAtom ** aAtom)
michael@0 712 {
michael@0 713 *aAtom = nullptr;
michael@0 714 switch (aProperty) {
michael@0 715 case eCSSEditableProperty_background_color:
michael@0 716 *aAtom = nsEditProperty::cssBackgroundColor;
michael@0 717 break;
michael@0 718 case eCSSEditableProperty_background_image:
michael@0 719 *aAtom = nsEditProperty::cssBackgroundImage;
michael@0 720 break;
michael@0 721 case eCSSEditableProperty_border:
michael@0 722 *aAtom = nsEditProperty::cssBorder;
michael@0 723 break;
michael@0 724 case eCSSEditableProperty_caption_side:
michael@0 725 *aAtom = nsEditProperty::cssCaptionSide;
michael@0 726 break;
michael@0 727 case eCSSEditableProperty_color:
michael@0 728 *aAtom = nsEditProperty::cssColor;
michael@0 729 break;
michael@0 730 case eCSSEditableProperty_float:
michael@0 731 *aAtom = nsEditProperty::cssFloat;
michael@0 732 break;
michael@0 733 case eCSSEditableProperty_font_family:
michael@0 734 *aAtom = nsEditProperty::cssFontFamily;
michael@0 735 break;
michael@0 736 case eCSSEditableProperty_font_size:
michael@0 737 *aAtom = nsEditProperty::cssFontSize;
michael@0 738 break;
michael@0 739 case eCSSEditableProperty_font_style:
michael@0 740 *aAtom = nsEditProperty::cssFontStyle;
michael@0 741 break;
michael@0 742 case eCSSEditableProperty_font_weight:
michael@0 743 *aAtom = nsEditProperty::cssFontWeight;
michael@0 744 break;
michael@0 745 case eCSSEditableProperty_height:
michael@0 746 *aAtom = nsEditProperty::cssHeight;
michael@0 747 break;
michael@0 748 case eCSSEditableProperty_list_style_type:
michael@0 749 *aAtom = nsEditProperty::cssListStyleType;
michael@0 750 break;
michael@0 751 case eCSSEditableProperty_margin_left:
michael@0 752 *aAtom = nsEditProperty::cssMarginLeft;
michael@0 753 break;
michael@0 754 case eCSSEditableProperty_margin_right:
michael@0 755 *aAtom = nsEditProperty::cssMarginRight;
michael@0 756 break;
michael@0 757 case eCSSEditableProperty_text_align:
michael@0 758 *aAtom = nsEditProperty::cssTextAlign;
michael@0 759 break;
michael@0 760 case eCSSEditableProperty_text_decoration:
michael@0 761 *aAtom = nsEditProperty::cssTextDecoration;
michael@0 762 break;
michael@0 763 case eCSSEditableProperty_vertical_align:
michael@0 764 *aAtom = nsEditProperty::cssVerticalAlign;
michael@0 765 break;
michael@0 766 case eCSSEditableProperty_whitespace:
michael@0 767 *aAtom = nsEditProperty::cssWhitespace;
michael@0 768 break;
michael@0 769 case eCSSEditableProperty_width:
michael@0 770 *aAtom = nsEditProperty::cssWidth;
michael@0 771 break;
michael@0 772 case eCSSEditableProperty_NONE:
michael@0 773 // intentionally empty
michael@0 774 break;
michael@0 775 }
michael@0 776 }
michael@0 777
michael@0 778 // Populate aProperty and aValueArray with the CSS declarations equivalent to the
michael@0 779 // value aValue according to the equivalence table aEquivTable
michael@0 780 void
michael@0 781 nsHTMLCSSUtils::BuildCSSDeclarations(nsTArray<nsIAtom*> & aPropertyArray,
michael@0 782 nsTArray<nsString> & aValueArray,
michael@0 783 const CSSEquivTable * aEquivTable,
michael@0 784 const nsAString * aValue,
michael@0 785 bool aGetOrRemoveRequest)
michael@0 786 {
michael@0 787 // clear arrays
michael@0 788 aPropertyArray.Clear();
michael@0 789 aValueArray.Clear();
michael@0 790
michael@0 791 // if we have an input value, let's use it
michael@0 792 nsAutoString value, lowerCasedValue;
michael@0 793 if (aValue) {
michael@0 794 value.Assign(*aValue);
michael@0 795 lowerCasedValue.Assign(*aValue);
michael@0 796 ToLowerCase(lowerCasedValue);
michael@0 797 }
michael@0 798
michael@0 799 int8_t index = 0;
michael@0 800 nsCSSEditableProperty cssProperty = aEquivTable[index].cssProperty;
michael@0 801 while (cssProperty) {
michael@0 802 if (!aGetOrRemoveRequest|| aEquivTable[index].gettable) {
michael@0 803 nsAutoString cssValue, cssPropertyString;
michael@0 804 nsIAtom * cssPropertyAtom;
michael@0 805 // find the equivalent css value for the index-th property in
michael@0 806 // the equivalence table
michael@0 807 (*aEquivTable[index].processValueFunctor) ((!aGetOrRemoveRequest || aEquivTable[index].caseSensitiveValue) ? &value : &lowerCasedValue,
michael@0 808 cssValue,
michael@0 809 aEquivTable[index].defaultValue,
michael@0 810 aEquivTable[index].prependValue,
michael@0 811 aEquivTable[index].appendValue);
michael@0 812 GetCSSPropertyAtom(cssProperty, &cssPropertyAtom);
michael@0 813 aPropertyArray.AppendElement(cssPropertyAtom);
michael@0 814 aValueArray.AppendElement(cssValue);
michael@0 815 }
michael@0 816 index++;
michael@0 817 cssProperty = aEquivTable[index].cssProperty;
michael@0 818 }
michael@0 819 }
michael@0 820
michael@0 821 // Populate cssPropertyArray and cssValueArray with the declarations equivalent
michael@0 822 // to aHTMLProperty/aAttribute/aValue for the node aNode
michael@0 823 void
michael@0 824 nsHTMLCSSUtils::GenerateCSSDeclarationsFromHTMLStyle(dom::Element* aElement,
michael@0 825 nsIAtom* aHTMLProperty,
michael@0 826 const nsAString* aAttribute,
michael@0 827 const nsAString* aValue,
michael@0 828 nsTArray<nsIAtom*>& cssPropertyArray,
michael@0 829 nsTArray<nsString>& cssValueArray,
michael@0 830 bool aGetOrRemoveRequest)
michael@0 831 {
michael@0 832 MOZ_ASSERT(aElement);
michael@0 833 nsIAtom* tagName = aElement->Tag();
michael@0 834 const nsHTMLCSSUtils::CSSEquivTable* equivTable = nullptr;
michael@0 835
michael@0 836 if (nsEditProperty::b == aHTMLProperty) {
michael@0 837 equivTable = boldEquivTable;
michael@0 838 } else if (nsEditProperty::i == aHTMLProperty) {
michael@0 839 equivTable = italicEquivTable;
michael@0 840 } else if (nsEditProperty::u == aHTMLProperty) {
michael@0 841 equivTable = underlineEquivTable;
michael@0 842 } else if (nsEditProperty::strike == aHTMLProperty) {
michael@0 843 equivTable = strikeEquivTable;
michael@0 844 } else if (nsEditProperty::tt == aHTMLProperty) {
michael@0 845 equivTable = ttEquivTable;
michael@0 846 } else if (aAttribute) {
michael@0 847 if (nsEditProperty::font == aHTMLProperty &&
michael@0 848 aAttribute->EqualsLiteral("color")) {
michael@0 849 equivTable = fontColorEquivTable;
michael@0 850 } else if (nsEditProperty::font == aHTMLProperty &&
michael@0 851 aAttribute->EqualsLiteral("face")) {
michael@0 852 equivTable = fontFaceEquivTable;
michael@0 853 } else if (aAttribute->EqualsLiteral("bgcolor")) {
michael@0 854 equivTable = bgcolorEquivTable;
michael@0 855 } else if (aAttribute->EqualsLiteral("background")) {
michael@0 856 equivTable = backgroundImageEquivTable;
michael@0 857 } else if (aAttribute->EqualsLiteral("text")) {
michael@0 858 equivTable = textColorEquivTable;
michael@0 859 } else if (aAttribute->EqualsLiteral("border")) {
michael@0 860 equivTable = borderEquivTable;
michael@0 861 } else if (aAttribute->EqualsLiteral("align")) {
michael@0 862 if (nsEditProperty::table == tagName) {
michael@0 863 equivTable = tableAlignEquivTable;
michael@0 864 } else if (nsEditProperty::hr == tagName) {
michael@0 865 equivTable = hrAlignEquivTable;
michael@0 866 } else if (nsEditProperty::legend == tagName ||
michael@0 867 nsEditProperty::caption == tagName) {
michael@0 868 equivTable = captionAlignEquivTable;
michael@0 869 } else {
michael@0 870 equivTable = textAlignEquivTable;
michael@0 871 }
michael@0 872 } else if (aAttribute->EqualsLiteral("valign")) {
michael@0 873 equivTable = verticalAlignEquivTable;
michael@0 874 } else if (aAttribute->EqualsLiteral("nowrap")) {
michael@0 875 equivTable = nowrapEquivTable;
michael@0 876 } else if (aAttribute->EqualsLiteral("width")) {
michael@0 877 equivTable = widthEquivTable;
michael@0 878 } else if (aAttribute->EqualsLiteral("height") ||
michael@0 879 (nsEditProperty::hr == tagName &&
michael@0 880 aAttribute->EqualsLiteral("size"))) {
michael@0 881 equivTable = heightEquivTable;
michael@0 882 } else if (aAttribute->EqualsLiteral("type") &&
michael@0 883 (nsEditProperty::ol == tagName
michael@0 884 || nsEditProperty::ul == tagName
michael@0 885 || nsEditProperty::li == tagName)) {
michael@0 886 equivTable = listStyleTypeEquivTable;
michael@0 887 }
michael@0 888 }
michael@0 889 if (equivTable) {
michael@0 890 BuildCSSDeclarations(cssPropertyArray, cssValueArray, equivTable,
michael@0 891 aValue, aGetOrRemoveRequest);
michael@0 892 }
michael@0 893 }
michael@0 894
michael@0 895 // Add to aNode the CSS inline style equivalent to HTMLProperty/aAttribute/
michael@0 896 // aValue for the node, and return in aCount the number of CSS properties set
michael@0 897 // by the call. The dom::Element version returns aCount instead.
michael@0 898 int32_t
michael@0 899 nsHTMLCSSUtils::SetCSSEquivalentToHTMLStyle(dom::Element* aElement,
michael@0 900 nsIAtom* aProperty,
michael@0 901 const nsAString* aAttribute,
michael@0 902 const nsAString* aValue,
michael@0 903 bool aSuppressTransaction)
michael@0 904 {
michael@0 905 MOZ_ASSERT(aElement && aProperty);
michael@0 906 MOZ_ASSERT_IF(aAttribute, aValue);
michael@0 907 int32_t count;
michael@0 908 // This can only fail if SetCSSProperty fails, which should only happen if
michael@0 909 // something is pretty badly wrong. In this case we assert so that hopefully
michael@0 910 // someone will notice, but there's nothing more sensible to do than just
michael@0 911 // return the count and carry on.
michael@0 912 nsresult res = SetCSSEquivalentToHTMLStyle(aElement->AsDOMNode(),
michael@0 913 aProperty, aAttribute,
michael@0 914 aValue, &count,
michael@0 915 aSuppressTransaction);
michael@0 916 NS_ASSERTION(NS_SUCCEEDED(res), "SetCSSEquivalentToHTMLStyle failed");
michael@0 917 NS_ENSURE_SUCCESS(res, count);
michael@0 918 return count;
michael@0 919 }
michael@0 920
michael@0 921 nsresult
michael@0 922 nsHTMLCSSUtils::SetCSSEquivalentToHTMLStyle(nsIDOMNode * aNode,
michael@0 923 nsIAtom *aHTMLProperty,
michael@0 924 const nsAString *aAttribute,
michael@0 925 const nsAString *aValue,
michael@0 926 int32_t * aCount,
michael@0 927 bool aSuppressTransaction)
michael@0 928 {
michael@0 929 nsCOMPtr<dom::Element> element = do_QueryInterface(aNode);
michael@0 930 *aCount = 0;
michael@0 931 if (!element || !IsCSSEditableProperty(element, aHTMLProperty, aAttribute)) {
michael@0 932 return NS_OK;
michael@0 933 }
michael@0 934
michael@0 935 // we can apply the styles only if the node is an element and if we have
michael@0 936 // an equivalence for the requested HTML style in this implementation
michael@0 937
michael@0 938 // Find the CSS equivalence to the HTML style
michael@0 939 nsTArray<nsIAtom*> cssPropertyArray;
michael@0 940 nsTArray<nsString> cssValueArray;
michael@0 941 GenerateCSSDeclarationsFromHTMLStyle(element, aHTMLProperty, aAttribute,
michael@0 942 aValue, cssPropertyArray, cssValueArray,
michael@0 943 false);
michael@0 944
michael@0 945 nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(element);
michael@0 946 // set the individual CSS inline styles
michael@0 947 *aCount = cssPropertyArray.Length();
michael@0 948 for (int32_t index = 0; index < *aCount; index++) {
michael@0 949 nsresult res = SetCSSProperty(domElement, cssPropertyArray[index],
michael@0 950 cssValueArray[index], aSuppressTransaction);
michael@0 951 NS_ENSURE_SUCCESS(res, res);
michael@0 952 }
michael@0 953 return NS_OK;
michael@0 954 }
michael@0 955
michael@0 956 // Remove from aNode the CSS inline style equivalent to HTMLProperty/aAttribute/aValue for the node
michael@0 957 nsresult
michael@0 958 nsHTMLCSSUtils::RemoveCSSEquivalentToHTMLStyle(nsIDOMNode * aNode,
michael@0 959 nsIAtom *aHTMLProperty,
michael@0 960 const nsAString *aAttribute,
michael@0 961 const nsAString *aValue,
michael@0 962 bool aSuppressTransaction)
michael@0 963 {
michael@0 964 nsCOMPtr<dom::Element> element = do_QueryInterface(aNode);
michael@0 965 NS_ENSURE_TRUE(element, NS_OK);
michael@0 966
michael@0 967 return RemoveCSSEquivalentToHTMLStyle(element, aHTMLProperty, aAttribute,
michael@0 968 aValue, aSuppressTransaction);
michael@0 969 }
michael@0 970
michael@0 971 nsresult
michael@0 972 nsHTMLCSSUtils::RemoveCSSEquivalentToHTMLStyle(dom::Element* aElement,
michael@0 973 nsIAtom* aHTMLProperty,
michael@0 974 const nsAString* aAttribute,
michael@0 975 const nsAString* aValue,
michael@0 976 bool aSuppressTransaction)
michael@0 977 {
michael@0 978 MOZ_ASSERT(aElement);
michael@0 979
michael@0 980 if (!IsCSSEditableProperty(aElement, aHTMLProperty, aAttribute)) {
michael@0 981 return NS_OK;
michael@0 982 }
michael@0 983
michael@0 984 // we can apply the styles only if the node is an element and if we have
michael@0 985 // an equivalence for the requested HTML style in this implementation
michael@0 986
michael@0 987 // Find the CSS equivalence to the HTML style
michael@0 988 nsTArray<nsIAtom*> cssPropertyArray;
michael@0 989 nsTArray<nsString> cssValueArray;
michael@0 990 GenerateCSSDeclarationsFromHTMLStyle(aElement, aHTMLProperty, aAttribute,
michael@0 991 aValue, cssPropertyArray, cssValueArray,
michael@0 992 true);
michael@0 993
michael@0 994 nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(aElement);
michael@0 995 // remove the individual CSS inline styles
michael@0 996 int32_t count = cssPropertyArray.Length();
michael@0 997 for (int32_t index = 0; index < count; index++) {
michael@0 998 nsresult res = RemoveCSSProperty(domElement,
michael@0 999 cssPropertyArray[index],
michael@0 1000 cssValueArray[index],
michael@0 1001 aSuppressTransaction);
michael@0 1002 NS_ENSURE_SUCCESS(res, res);
michael@0 1003 }
michael@0 1004 return NS_OK;
michael@0 1005 }
michael@0 1006
michael@0 1007 // returns in aValueString the list of values for the CSS equivalences to
michael@0 1008 // the HTML style aHTMLProperty/aAttribute/aValueString for the node aNode;
michael@0 1009 // the value of aStyleType controls the styles we retrieve : specified or
michael@0 1010 // computed.
michael@0 1011 nsresult
michael@0 1012 nsHTMLCSSUtils::GetCSSEquivalentToHTMLInlineStyleSet(nsINode* aNode,
michael@0 1013 nsIAtom *aHTMLProperty,
michael@0 1014 const nsAString *aAttribute,
michael@0 1015 nsAString & aValueString,
michael@0 1016 StyleType aStyleType)
michael@0 1017 {
michael@0 1018 aValueString.Truncate();
michael@0 1019 nsCOMPtr<dom::Element> theElement = GetElementContainerOrSelf(aNode);
michael@0 1020 NS_ENSURE_TRUE(theElement, NS_ERROR_NULL_POINTER);
michael@0 1021
michael@0 1022 if (!theElement || !IsCSSEditableProperty(theElement, aHTMLProperty, aAttribute)) {
michael@0 1023 return NS_OK;
michael@0 1024 }
michael@0 1025
michael@0 1026 // Yes, the requested HTML style has a CSS equivalence in this implementation
michael@0 1027 nsTArray<nsIAtom*> cssPropertyArray;
michael@0 1028 nsTArray<nsString> cssValueArray;
michael@0 1029 // get the CSS equivalence with last param true indicating we want only the
michael@0 1030 // "gettable" properties
michael@0 1031 GenerateCSSDeclarationsFromHTMLStyle(theElement, aHTMLProperty, aAttribute, nullptr,
michael@0 1032 cssPropertyArray, cssValueArray, true);
michael@0 1033 int32_t count = cssPropertyArray.Length();
michael@0 1034 for (int32_t index = 0; index < count; index++) {
michael@0 1035 nsAutoString valueString;
michael@0 1036 // retrieve the specified/computed value of the property
michael@0 1037 nsresult res = GetCSSInlinePropertyBase(theElement, cssPropertyArray[index],
michael@0 1038 valueString, aStyleType);
michael@0 1039 NS_ENSURE_SUCCESS(res, res);
michael@0 1040 // append the value to aValueString (possibly with a leading whitespace)
michael@0 1041 if (index) {
michael@0 1042 aValueString.Append(char16_t(' '));
michael@0 1043 }
michael@0 1044 aValueString.Append(valueString);
michael@0 1045 }
michael@0 1046 return NS_OK;
michael@0 1047 }
michael@0 1048
michael@0 1049 // Does the node aNode (or its parent, if it's not an element node) have a CSS
michael@0 1050 // style equivalent to the HTML style aHTMLProperty/aHTMLAttribute/valueString?
michael@0 1051 // The value of aStyleType controls the styles we retrieve: specified or
michael@0 1052 // computed. The return value aIsSet is true if the CSS styles are set.
michael@0 1053 //
michael@0 1054 // The nsIContent variant returns aIsSet instead of using an out parameter, and
michael@0 1055 // does not modify aValue.
michael@0 1056 bool
michael@0 1057 nsHTMLCSSUtils::IsCSSEquivalentToHTMLInlineStyleSet(nsIContent* aContent,
michael@0 1058 nsIAtom* aProperty,
michael@0 1059 const nsAString* aAttribute,
michael@0 1060 const nsAString& aValue,
michael@0 1061 StyleType aStyleType)
michael@0 1062 {
michael@0 1063 MOZ_ASSERT(aContent && aProperty);
michael@0 1064 bool isSet;
michael@0 1065 nsAutoString value(aValue);
michael@0 1066 nsresult res = IsCSSEquivalentToHTMLInlineStyleSet(aContent->AsDOMNode(),
michael@0 1067 aProperty, aAttribute,
michael@0 1068 isSet, value, aStyleType);
michael@0 1069 NS_ASSERTION(NS_SUCCEEDED(res), "IsCSSEquivalentToHTMLInlineStyleSet failed");
michael@0 1070 NS_ENSURE_SUCCESS(res, false);
michael@0 1071 return isSet;
michael@0 1072 }
michael@0 1073
michael@0 1074 nsresult
michael@0 1075 nsHTMLCSSUtils::IsCSSEquivalentToHTMLInlineStyleSet(nsIDOMNode *aNode,
michael@0 1076 nsIAtom *aHTMLProperty,
michael@0 1077 const nsAString *aHTMLAttribute,
michael@0 1078 bool& aIsSet,
michael@0 1079 nsAString& valueString,
michael@0 1080 StyleType aStyleType)
michael@0 1081 {
michael@0 1082 NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
michael@0 1083
michael@0 1084 nsAutoString htmlValueString(valueString);
michael@0 1085 aIsSet = false;
michael@0 1086 nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
michael@0 1087 do {
michael@0 1088 valueString.Assign(htmlValueString);
michael@0 1089 // get the value of the CSS equivalent styles
michael@0 1090 nsresult res = GetCSSEquivalentToHTMLInlineStyleSet(node, aHTMLProperty, aHTMLAttribute,
michael@0 1091 valueString, aStyleType);
michael@0 1092 NS_ENSURE_SUCCESS(res, res);
michael@0 1093
michael@0 1094 // early way out if we can
michael@0 1095 if (valueString.IsEmpty()) {
michael@0 1096 return NS_OK;
michael@0 1097 }
michael@0 1098
michael@0 1099 if (nsEditProperty::b == aHTMLProperty) {
michael@0 1100 if (valueString.EqualsLiteral("bold")) {
michael@0 1101 aIsSet = true;
michael@0 1102 } else if (valueString.EqualsLiteral("normal")) {
michael@0 1103 aIsSet = false;
michael@0 1104 } else if (valueString.EqualsLiteral("bolder")) {
michael@0 1105 aIsSet = true;
michael@0 1106 valueString.AssignLiteral("bold");
michael@0 1107 } else {
michael@0 1108 int32_t weight = 0;
michael@0 1109 nsresult errorCode;
michael@0 1110 nsAutoString value(valueString);
michael@0 1111 weight = value.ToInteger(&errorCode);
michael@0 1112 if (400 < weight) {
michael@0 1113 aIsSet = true;
michael@0 1114 valueString.AssignLiteral("bold");
michael@0 1115 } else {
michael@0 1116 aIsSet = false;
michael@0 1117 valueString.AssignLiteral("normal");
michael@0 1118 }
michael@0 1119 }
michael@0 1120 } else if (nsEditProperty::i == aHTMLProperty) {
michael@0 1121 if (valueString.EqualsLiteral("italic") ||
michael@0 1122 valueString.EqualsLiteral("oblique")) {
michael@0 1123 aIsSet = true;
michael@0 1124 }
michael@0 1125 } else if (nsEditProperty::u == aHTMLProperty) {
michael@0 1126 nsAutoString val;
michael@0 1127 val.AssignLiteral("underline");
michael@0 1128 aIsSet = bool(ChangeCSSInlineStyleTxn::ValueIncludes(valueString, val, false));
michael@0 1129 } else if (nsEditProperty::strike == aHTMLProperty) {
michael@0 1130 nsAutoString val;
michael@0 1131 val.AssignLiteral("line-through");
michael@0 1132 aIsSet = bool(ChangeCSSInlineStyleTxn::ValueIncludes(valueString, val, false));
michael@0 1133 } else if (aHTMLAttribute &&
michael@0 1134 ((nsEditProperty::font == aHTMLProperty &&
michael@0 1135 aHTMLAttribute->EqualsLiteral("color")) ||
michael@0 1136 aHTMLAttribute->EqualsLiteral("bgcolor"))) {
michael@0 1137 if (htmlValueString.IsEmpty()) {
michael@0 1138 aIsSet = true;
michael@0 1139 } else {
michael@0 1140 nscolor rgba;
michael@0 1141 nsAutoString subStr;
michael@0 1142 htmlValueString.Right(subStr, htmlValueString.Length() - 1);
michael@0 1143 if (NS_ColorNameToRGB(htmlValueString, &rgba) ||
michael@0 1144 NS_HexToRGB(subStr, &rgba)) {
michael@0 1145 nsAutoString htmlColor, tmpStr;
michael@0 1146
michael@0 1147 if (NS_GET_A(rgba) != 255) {
michael@0 1148 // This should only be hit by the "transparent" keyword, which
michael@0 1149 // currently serializes to "transparent" (not "rgba(0, 0, 0, 0)").
michael@0 1150 MOZ_ASSERT(NS_GET_R(rgba) == 0 && NS_GET_G(rgba) == 0 &&
michael@0 1151 NS_GET_B(rgba) == 0 && NS_GET_A(rgba) == 0);
michael@0 1152 htmlColor.AppendLiteral("transparent");
michael@0 1153 } else {
michael@0 1154 htmlColor.AppendLiteral("rgb(");
michael@0 1155
michael@0 1156 NS_NAMED_LITERAL_STRING(comma, ", ");
michael@0 1157
michael@0 1158 tmpStr.AppendInt(NS_GET_R(rgba), 10);
michael@0 1159 htmlColor.Append(tmpStr + comma);
michael@0 1160
michael@0 1161 tmpStr.Truncate();
michael@0 1162 tmpStr.AppendInt(NS_GET_G(rgba), 10);
michael@0 1163 htmlColor.Append(tmpStr + comma);
michael@0 1164
michael@0 1165 tmpStr.Truncate();
michael@0 1166 tmpStr.AppendInt(NS_GET_B(rgba), 10);
michael@0 1167 htmlColor.Append(tmpStr);
michael@0 1168
michael@0 1169 htmlColor.Append(char16_t(')'));
michael@0 1170 }
michael@0 1171
michael@0 1172 aIsSet = htmlColor.Equals(valueString,
michael@0 1173 nsCaseInsensitiveStringComparator());
michael@0 1174 } else {
michael@0 1175 aIsSet = htmlValueString.Equals(valueString,
michael@0 1176 nsCaseInsensitiveStringComparator());
michael@0 1177 }
michael@0 1178 }
michael@0 1179 } else if (nsEditProperty::tt == aHTMLProperty) {
michael@0 1180 aIsSet = StringBeginsWith(valueString, NS_LITERAL_STRING("monospace"));
michael@0 1181 } else if (nsEditProperty::font == aHTMLProperty && aHTMLAttribute &&
michael@0 1182 aHTMLAttribute->EqualsLiteral("face")) {
michael@0 1183 if (!htmlValueString.IsEmpty()) {
michael@0 1184 const char16_t commaSpace[] = { char16_t(','), char16_t(' '), 0 };
michael@0 1185 const char16_t comma[] = { char16_t(','), 0 };
michael@0 1186 htmlValueString.ReplaceSubstring(commaSpace, comma);
michael@0 1187 nsAutoString valueStringNorm(valueString);
michael@0 1188 valueStringNorm.ReplaceSubstring(commaSpace, comma);
michael@0 1189 aIsSet = htmlValueString.Equals(valueStringNorm,
michael@0 1190 nsCaseInsensitiveStringComparator());
michael@0 1191 } else {
michael@0 1192 // ignore this, it's TT or our default
michael@0 1193 nsAutoString valueStringLower;
michael@0 1194 ToLowerCase(valueString, valueStringLower);
michael@0 1195 aIsSet = !valueStringLower.EqualsLiteral("monospace") &&
michael@0 1196 !valueStringLower.EqualsLiteral("serif");
michael@0 1197 }
michael@0 1198 return NS_OK;
michael@0 1199 } else if (aHTMLAttribute && aHTMLAttribute->EqualsLiteral("align")) {
michael@0 1200 aIsSet = true;
michael@0 1201 } else {
michael@0 1202 aIsSet = false;
michael@0 1203 return NS_OK;
michael@0 1204 }
michael@0 1205
michael@0 1206 if (!htmlValueString.IsEmpty() &&
michael@0 1207 htmlValueString.Equals(valueString,
michael@0 1208 nsCaseInsensitiveStringComparator())) {
michael@0 1209 aIsSet = true;
michael@0 1210 }
michael@0 1211
michael@0 1212 if (htmlValueString.EqualsLiteral("-moz-editor-invert-value")) {
michael@0 1213 aIsSet = !aIsSet;
michael@0 1214 }
michael@0 1215
michael@0 1216 if (nsEditProperty::u == aHTMLProperty || nsEditProperty::strike == aHTMLProperty) {
michael@0 1217 // unfortunately, the value of the text-decoration property is not inherited.
michael@0 1218 // that means that we have to look at ancestors of node to see if they are underlined
michael@0 1219 node = node->GetParentElement(); // set to null if it's not a dom element
michael@0 1220 }
michael@0 1221 } while ((nsEditProperty::u == aHTMLProperty || nsEditProperty::strike == aHTMLProperty) &&
michael@0 1222 !aIsSet && node);
michael@0 1223 return NS_OK;
michael@0 1224 }
michael@0 1225
michael@0 1226 void
michael@0 1227 nsHTMLCSSUtils::SetCSSEnabled(bool aIsCSSPrefChecked)
michael@0 1228 {
michael@0 1229 mIsCSSPrefChecked = aIsCSSPrefChecked;
michael@0 1230 }
michael@0 1231
michael@0 1232 bool
michael@0 1233 nsHTMLCSSUtils::IsCSSPrefChecked()
michael@0 1234 {
michael@0 1235 return mIsCSSPrefChecked ;
michael@0 1236 }
michael@0 1237
michael@0 1238 // ElementsSameStyle compares two elements and checks if they have the same
michael@0 1239 // specified CSS declarations in the STYLE attribute
michael@0 1240 // The answer is always negative if at least one of them carries an ID or a class
michael@0 1241 bool
michael@0 1242 nsHTMLCSSUtils::ElementsSameStyle(nsIDOMNode *aFirstNode, nsIDOMNode *aSecondNode)
michael@0 1243 {
michael@0 1244 nsCOMPtr<dom::Element> firstElement = do_QueryInterface(aFirstNode);
michael@0 1245 nsCOMPtr<dom::Element> secondElement = do_QueryInterface(aSecondNode);
michael@0 1246
michael@0 1247 NS_ASSERTION((firstElement && secondElement), "Non element nodes passed to ElementsSameStyle.");
michael@0 1248 NS_ENSURE_TRUE(firstElement, false);
michael@0 1249 NS_ENSURE_TRUE(secondElement, false);
michael@0 1250
michael@0 1251 return ElementsSameStyle(firstElement, secondElement);
michael@0 1252 }
michael@0 1253
michael@0 1254 bool
michael@0 1255 nsHTMLCSSUtils::ElementsSameStyle(dom::Element* aFirstElement,
michael@0 1256 dom::Element* aSecondElement)
michael@0 1257 {
michael@0 1258 MOZ_ASSERT(aFirstElement);
michael@0 1259 MOZ_ASSERT(aSecondElement);
michael@0 1260
michael@0 1261 if (aFirstElement->HasAttr(kNameSpaceID_None, nsGkAtoms::id) ||
michael@0 1262 aSecondElement->HasAttr(kNameSpaceID_None, nsGkAtoms::id)) {
michael@0 1263 // at least one of the spans carries an ID ; suspect a CSS rule applies to it and
michael@0 1264 // refuse to merge the nodes
michael@0 1265 return false;
michael@0 1266 }
michael@0 1267
michael@0 1268 nsAutoString firstClass, secondClass;
michael@0 1269 bool isFirstClassSet = aFirstElement->GetAttr(kNameSpaceID_None, nsGkAtoms::_class, firstClass);
michael@0 1270 bool isSecondClassSet = aSecondElement->GetAttr(kNameSpaceID_None, nsGkAtoms::_class, secondClass);
michael@0 1271 if (isFirstClassSet && isSecondClassSet) {
michael@0 1272 // both spans carry a class, let's compare them
michael@0 1273 if (!firstClass.Equals(secondClass)) {
michael@0 1274 // WARNING : technically, the comparison just above is questionable :
michael@0 1275 // from a pure HTML/CSS point of view class="a b" is NOT the same than
michael@0 1276 // class="b a" because a CSS rule could test the exact value of the class
michael@0 1277 // attribute to be "a b" for instance ; from a user's point of view, a
michael@0 1278 // wysiwyg editor should probably NOT make any difference. CSS people
michael@0 1279 // need to discuss this issue before any modification.
michael@0 1280 return false;
michael@0 1281 }
michael@0 1282 } else if (isFirstClassSet || isSecondClassSet) {
michael@0 1283 // one span only carries a class, early way out
michael@0 1284 return false;
michael@0 1285 }
michael@0 1286
michael@0 1287 nsCOMPtr<nsIDOMCSSStyleDeclaration> firstCSSDecl, secondCSSDecl;
michael@0 1288 uint32_t firstLength, secondLength;
michael@0 1289 nsresult rv = GetInlineStyles(aFirstElement, getter_AddRefs(firstCSSDecl), &firstLength);
michael@0 1290 if (NS_FAILED(rv) || !firstCSSDecl) {
michael@0 1291 return false;
michael@0 1292 }
michael@0 1293 rv = GetInlineStyles(aSecondElement, getter_AddRefs(secondCSSDecl), &secondLength);
michael@0 1294 if (NS_FAILED(rv) || !secondCSSDecl) {
michael@0 1295 return false;
michael@0 1296 }
michael@0 1297
michael@0 1298 if (firstLength != secondLength) {
michael@0 1299 // early way out if we can
michael@0 1300 return false;
michael@0 1301 }
michael@0 1302
michael@0 1303 if (!firstLength) {
michael@0 1304 // no inline style !
michael@0 1305 return true;
michael@0 1306 }
michael@0 1307
michael@0 1308 nsAutoString propertyNameString;
michael@0 1309 nsAutoString firstValue, secondValue;
michael@0 1310 for (uint32_t i = 0; i < firstLength; i++) {
michael@0 1311 firstCSSDecl->Item(i, propertyNameString);
michael@0 1312 firstCSSDecl->GetPropertyValue(propertyNameString, firstValue);
michael@0 1313 secondCSSDecl->GetPropertyValue(propertyNameString, secondValue);
michael@0 1314 if (!firstValue.Equals(secondValue)) {
michael@0 1315 return false;
michael@0 1316 }
michael@0 1317 }
michael@0 1318 for (uint32_t i = 0; i < secondLength; i++) {
michael@0 1319 secondCSSDecl->Item(i, propertyNameString);
michael@0 1320 secondCSSDecl->GetPropertyValue(propertyNameString, secondValue);
michael@0 1321 firstCSSDecl->GetPropertyValue(propertyNameString, firstValue);
michael@0 1322 if (!firstValue.Equals(secondValue)) {
michael@0 1323 return false;
michael@0 1324 }
michael@0 1325 }
michael@0 1326
michael@0 1327 return true;
michael@0 1328 }
michael@0 1329
michael@0 1330 nsresult
michael@0 1331 nsHTMLCSSUtils::GetInlineStyles(dom::Element* aElement,
michael@0 1332 nsIDOMCSSStyleDeclaration** aCssDecl,
michael@0 1333 uint32_t* aLength)
michael@0 1334 {
michael@0 1335 return GetInlineStyles(static_cast<nsISupports*>(aElement), aCssDecl, aLength);
michael@0 1336 }
michael@0 1337
michael@0 1338 nsresult
michael@0 1339 nsHTMLCSSUtils::GetInlineStyles(nsIDOMElement* aElement,
michael@0 1340 nsIDOMCSSStyleDeclaration** aCssDecl,
michael@0 1341 uint32_t* aLength)
michael@0 1342 {
michael@0 1343 return GetInlineStyles(static_cast<nsISupports*>(aElement), aCssDecl, aLength);
michael@0 1344 }
michael@0 1345
michael@0 1346 nsresult
michael@0 1347 nsHTMLCSSUtils::GetInlineStyles(nsISupports *aElement,
michael@0 1348 nsIDOMCSSStyleDeclaration **aCssDecl,
michael@0 1349 uint32_t *aLength)
michael@0 1350 {
michael@0 1351 NS_ENSURE_TRUE(aElement && aLength, NS_ERROR_NULL_POINTER);
michael@0 1352 *aLength = 0;
michael@0 1353 nsCOMPtr<nsIDOMElementCSSInlineStyle> inlineStyles = do_QueryInterface(aElement);
michael@0 1354 NS_ENSURE_TRUE(inlineStyles, NS_ERROR_NULL_POINTER);
michael@0 1355
michael@0 1356 nsresult res = inlineStyles->GetStyle(aCssDecl);
michael@0 1357 NS_ENSURE_SUCCESS(res, NS_ERROR_NULL_POINTER);
michael@0 1358 MOZ_ASSERT(*aCssDecl);
michael@0 1359
michael@0 1360 (*aCssDecl)->GetLength(aLength);
michael@0 1361 return NS_OK;
michael@0 1362 }
michael@0 1363
michael@0 1364 already_AddRefed<nsIDOMElement>
michael@0 1365 nsHTMLCSSUtils::GetElementContainerOrSelf(nsIDOMNode* aNode)
michael@0 1366 {
michael@0 1367 nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
michael@0 1368 NS_ENSURE_TRUE(node, nullptr);
michael@0 1369 nsCOMPtr<nsIDOMElement> element =
michael@0 1370 do_QueryInterface(GetElementContainerOrSelf(node));
michael@0 1371 return element.forget();
michael@0 1372 }
michael@0 1373
michael@0 1374 dom::Element*
michael@0 1375 nsHTMLCSSUtils::GetElementContainerOrSelf(nsINode* aNode)
michael@0 1376 {
michael@0 1377 MOZ_ASSERT(aNode);
michael@0 1378 if (nsIDOMNode::DOCUMENT_NODE == aNode->NodeType()) {
michael@0 1379 return nullptr;
michael@0 1380 }
michael@0 1381
michael@0 1382 nsINode* node = aNode;
michael@0 1383 // Loop until we find an element.
michael@0 1384 while (node && !node->IsElement()) {
michael@0 1385 node = node->GetParentNode();
michael@0 1386 }
michael@0 1387
michael@0 1388 NS_ENSURE_TRUE(node, nullptr);
michael@0 1389 return node->AsElement();
michael@0 1390 }
michael@0 1391
michael@0 1392 nsresult
michael@0 1393 nsHTMLCSSUtils::SetCSSProperty(nsIDOMElement * aElement,
michael@0 1394 const nsAString & aProperty,
michael@0 1395 const nsAString & aValue)
michael@0 1396 {
michael@0 1397 nsCOMPtr<nsIDOMCSSStyleDeclaration> cssDecl;
michael@0 1398 uint32_t length;
michael@0 1399 nsresult res = GetInlineStyles(aElement, getter_AddRefs(cssDecl), &length);
michael@0 1400 if (NS_FAILED(res) || !cssDecl) return res;
michael@0 1401
michael@0 1402 return cssDecl->SetProperty(aProperty,
michael@0 1403 aValue,
michael@0 1404 EmptyString());
michael@0 1405 }
michael@0 1406
michael@0 1407 nsresult
michael@0 1408 nsHTMLCSSUtils::SetCSSPropertyPixels(nsIDOMElement * aElement,
michael@0 1409 const nsAString & aProperty,
michael@0 1410 int32_t aIntValue)
michael@0 1411 {
michael@0 1412 nsAutoString s;
michael@0 1413 s.AppendInt(aIntValue);
michael@0 1414 return SetCSSProperty(aElement, aProperty, s + NS_LITERAL_STRING("px"));
michael@0 1415 }

mercurial