layout/generic/nsFrameUtil.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 /* utilities for regression tests based on frame tree comparison */
michael@0 7
michael@0 8 #include "nsIFrameUtil.h"
michael@0 9 #include "nsFrame.h"
michael@0 10 #include "nsString.h"
michael@0 11 #include "nsRect.h"
michael@0 12 #include <stdlib.h>
michael@0 13 #include "plstr.h"
michael@0 14
michael@0 15
michael@0 16 #ifdef DEBUG
michael@0 17 class nsFrameUtil : public nsIFrameUtil {
michael@0 18 public:
michael@0 19 nsFrameUtil();
michael@0 20 virtual ~nsFrameUtil();
michael@0 21
michael@0 22 NS_DECL_ISUPPORTS
michael@0 23
michael@0 24 NS_IMETHOD CompareRegressionData(FILE* aFile1, FILE* aFile2,int32_t aRegressionOutput=0);
michael@0 25 NS_IMETHOD DumpRegressionData(FILE* aInputFile, FILE* aOutputFile);
michael@0 26
michael@0 27 struct Node;
michael@0 28 struct Tag;
michael@0 29
michael@0 30 struct NodeList {
michael@0 31 NodeList();
michael@0 32 ~NodeList();
michael@0 33
michael@0 34 static void Destroy(NodeList* aLists);
michael@0 35
michael@0 36 NodeList* next; // for lists of lists
michael@0 37 Node* node;
michael@0 38 char* name;
michael@0 39 };
michael@0 40
michael@0 41 struct Node {
michael@0 42 Node();
michael@0 43 ~Node();
michael@0 44
michael@0 45 static void Destroy(Node* aNode);
michael@0 46
michael@0 47 static Node* Read(FILE* aFile, Tag* aTag);
michael@0 48
michael@0 49 static Node* ReadTree(FILE* aFile);
michael@0 50
michael@0 51 Node* next;
michael@0 52 char* type;
michael@0 53 uint32_t state;
michael@0 54 nsRect bbox;
michael@0 55 nsCString styleData;
michael@0 56 NodeList* lists;
michael@0 57 };
michael@0 58
michael@0 59 struct Tag {
michael@0 60 Tag();
michael@0 61 ~Tag();
michael@0 62
michael@0 63 static Tag* Parse(FILE* aFile);
michael@0 64
michael@0 65 void AddAttr(char* aAttr, char* aValue);
michael@0 66
michael@0 67 const char* GetAttr(const char* aAttr);
michael@0 68
michael@0 69 void ReadAttrs(FILE* aFile);
michael@0 70
michael@0 71 void ToString(nsString& aResult);
michael@0 72
michael@0 73 enum Type {
michael@0 74 open,
michael@0 75 close,
michael@0 76 openClose
michael@0 77 };
michael@0 78
michael@0 79 char* name;
michael@0 80 Type type;
michael@0 81 char** attributes;
michael@0 82 int32_t num;
michael@0 83 int32_t size;
michael@0 84 char** values;
michael@0 85 };
michael@0 86
michael@0 87 static char* Copy(const char* aString);
michael@0 88
michael@0 89 static void DumpNode(Node* aNode, FILE* aOutputFile, int32_t aIndent);
michael@0 90 static void DumpTree(Node* aNode, FILE* aOutputFile, int32_t aIndent);
michael@0 91 static bool CompareTrees(Node* aNode1, Node* aNode2);
michael@0 92 };
michael@0 93
michael@0 94 char*
michael@0 95 nsFrameUtil::Copy(const char* aString)
michael@0 96 {
michael@0 97 if (aString) {
michael@0 98 int l = ::strlen(aString);
michael@0 99 char* c = new char[l+1];
michael@0 100 if (!c)
michael@0 101 return nullptr;
michael@0 102 memcpy(c, aString, l+1);
michael@0 103 return c;
michael@0 104 }
michael@0 105 return nullptr;
michael@0 106 }
michael@0 107
michael@0 108 //----------------------------------------------------------------------
michael@0 109
michael@0 110 nsFrameUtil::NodeList::NodeList()
michael@0 111 : next(nullptr), node(nullptr), name(nullptr)
michael@0 112 {
michael@0 113 }
michael@0 114
michael@0 115 nsFrameUtil::NodeList::~NodeList()
michael@0 116 {
michael@0 117 if (nullptr != name) {
michael@0 118 delete name;
michael@0 119 }
michael@0 120 if (nullptr != node) {
michael@0 121 Node::Destroy(node);
michael@0 122 }
michael@0 123 }
michael@0 124
michael@0 125 void
michael@0 126 nsFrameUtil::NodeList::Destroy(NodeList* aLists)
michael@0 127 {
michael@0 128 while (nullptr != aLists) {
michael@0 129 NodeList* next = aLists->next;
michael@0 130 delete aLists;
michael@0 131 aLists = next;
michael@0 132 }
michael@0 133 }
michael@0 134
michael@0 135 //----------------------------------------------------------------------
michael@0 136
michael@0 137 nsFrameUtil::Node::Node()
michael@0 138 : next(nullptr), type(nullptr), state(0), lists(nullptr)
michael@0 139 {
michael@0 140 }
michael@0 141
michael@0 142 nsFrameUtil::Node::~Node()
michael@0 143 {
michael@0 144 if (nullptr != type) {
michael@0 145 delete type;
michael@0 146 }
michael@0 147 if (nullptr != lists) {
michael@0 148 NodeList::Destroy(lists);
michael@0 149 }
michael@0 150 }
michael@0 151
michael@0 152 void
michael@0 153 nsFrameUtil::Node::Destroy(Node* aList)
michael@0 154 {
michael@0 155 while (nullptr != aList) {
michael@0 156 Node* next = aList->next;
michael@0 157 delete aList;
michael@0 158 aList = next;
michael@0 159 }
michael@0 160 }
michael@0 161
michael@0 162 static int32_t GetInt(nsFrameUtil::Tag* aTag, const char* aAttr)
michael@0 163 {
michael@0 164 const char* value = aTag->GetAttr(aAttr);
michael@0 165 if (nullptr != value) {
michael@0 166 return int32_t( atoi(value) );
michael@0 167 }
michael@0 168 return 0;
michael@0 169 }
michael@0 170
michael@0 171 nsFrameUtil::Node*
michael@0 172 nsFrameUtil::Node::ReadTree(FILE* aFile)
michael@0 173 {
michael@0 174 Tag* tag = Tag::Parse(aFile);
michael@0 175 if (nullptr == tag) {
michael@0 176 return nullptr;
michael@0 177 }
michael@0 178 if (PL_strcmp(tag->name, "frame") != 0) {
michael@0 179 delete tag;
michael@0 180 return nullptr;
michael@0 181 }
michael@0 182 Node* result = Read(aFile, tag);
michael@0 183 fclose(aFile);
michael@0 184 return result;
michael@0 185 }
michael@0 186
michael@0 187 nsFrameUtil::Node*
michael@0 188 nsFrameUtil::Node::Read(FILE* aFile, Tag* tag)
michael@0 189 {
michael@0 190 Node* node = new Node;
michael@0 191 node->type = Copy(tag->GetAttr("type"));
michael@0 192 if (!node->type) {
michael@0 193 /* crash() */
michael@0 194 }
michael@0 195 node->state = GetInt(tag, "state");
michael@0 196 delete tag;
michael@0 197
michael@0 198 for (;;) {
michael@0 199 tag = Tag::Parse(aFile);
michael@0 200 if (nullptr == tag) break;
michael@0 201 if (PL_strcmp(tag->name, "frame") == 0) {
michael@0 202 delete tag;
michael@0 203 break;
michael@0 204 }
michael@0 205 if (PL_strcmp(tag->name, "bbox") == 0) {
michael@0 206 nscoord x = nscoord( GetInt(tag, "x") );
michael@0 207 nscoord y = nscoord( GetInt(tag, "y") );
michael@0 208 nscoord w = nscoord( GetInt(tag, "w") );
michael@0 209 nscoord h = nscoord( GetInt(tag, "h") );
michael@0 210 node->bbox.SetRect(x, y, w, h);
michael@0 211 }
michael@0 212 else if (PL_strcmp(tag->name, "child-list") == 0) {
michael@0 213 NodeList* list = new NodeList();
michael@0 214 list->name = Copy(tag->GetAttr("name"));
michael@0 215 if (!list->name) {
michael@0 216 /* crash() */
michael@0 217 }
michael@0 218 list->next = node->lists;
michael@0 219 node->lists = list;
michael@0 220 delete tag;
michael@0 221
michael@0 222 Node** tailp = &list->node;
michael@0 223 for (;;) {
michael@0 224 tag = Tag::Parse(aFile);
michael@0 225 if (nullptr == tag) {
michael@0 226 break;
michael@0 227 }
michael@0 228 if (PL_strcmp(tag->name, "child-list") == 0) {
michael@0 229 break;
michael@0 230 }
michael@0 231 if (PL_strcmp(tag->name, "frame") != 0) {
michael@0 232 break;
michael@0 233 }
michael@0 234 Node* child = Node::Read(aFile, tag);
michael@0 235 if (nullptr == child) {
michael@0 236 break;
michael@0 237 }
michael@0 238 *tailp = child;
michael@0 239 tailp = &child->next;
michael@0 240 }
michael@0 241 }
michael@0 242 else if((PL_strcmp(tag->name, "font") == 0) ||
michael@0 243 (PL_strcmp(tag->name, "color") == 0) ||
michael@0 244 (PL_strcmp(tag->name, "spacing") == 0) ||
michael@0 245 (PL_strcmp(tag->name, "list") == 0) ||
michael@0 246 (PL_strcmp(tag->name, "position") == 0) ||
michael@0 247 (PL_strcmp(tag->name, "text") == 0) ||
michael@0 248 (PL_strcmp(tag->name, "display") == 0) ||
michael@0 249 (PL_strcmp(tag->name, "table") == 0) ||
michael@0 250 (PL_strcmp(tag->name, "content") == 0) ||
michael@0 251 (PL_strcmp(tag->name, "UI") == 0) ||
michael@0 252 (PL_strcmp(tag->name, "print") == 0)) {
michael@0 253 const char* attr = tag->GetAttr("data");
michael@0 254 node->styleData.Append('|');
michael@0 255 node->styleData.Append(attr ? attr : "null attr");
michael@0 256 }
michael@0 257
michael@0 258 delete tag;
michael@0 259 }
michael@0 260 return node;
michael@0 261 }
michael@0 262
michael@0 263 //----------------------------------------------------------------------
michael@0 264
michael@0 265 nsFrameUtil::Tag::Tag()
michael@0 266 : name(nullptr), type(open), attributes(nullptr), num(0), size(0),
michael@0 267 values(nullptr)
michael@0 268 {
michael@0 269 }
michael@0 270
michael@0 271 nsFrameUtil::Tag::~Tag()
michael@0 272 {
michael@0 273 int32_t i, n = num;
michael@0 274 if (0 != n) {
michael@0 275 for (i = 0; i < n; i++) {
michael@0 276 delete attributes[i];
michael@0 277 delete values[i];
michael@0 278 }
michael@0 279 delete attributes;
michael@0 280 delete values;
michael@0 281 }
michael@0 282 }
michael@0 283
michael@0 284 void
michael@0 285 nsFrameUtil::Tag::AddAttr(char* aAttr, char* aValue)
michael@0 286 {
michael@0 287 if (num == size) {
michael@0 288 int32_t newSize = size * 2 + 4;
michael@0 289 char** a = new char*[newSize];
michael@0 290 char** v = new char*[newSize];
michael@0 291 if (0 != num) {
michael@0 292 memcpy(a, attributes, num * sizeof(char*));
michael@0 293 memcpy(v, values, num * sizeof(char*));
michael@0 294 delete attributes;
michael@0 295 delete values;
michael@0 296 }
michael@0 297 attributes = a;
michael@0 298 values = v;
michael@0 299 size = newSize;
michael@0 300 }
michael@0 301 attributes[num] = aAttr;
michael@0 302 values[num] = aValue;
michael@0 303 num = num + 1;
michael@0 304 }
michael@0 305
michael@0 306 const char*
michael@0 307 nsFrameUtil::Tag::GetAttr(const char* aAttr)
michael@0 308 {
michael@0 309 int32_t i, n = num;
michael@0 310 for (i = 0; i < n; i++) {
michael@0 311 if (PL_strcmp(attributes[i], aAttr) == 0) {
michael@0 312 return values[i];
michael@0 313 }
michael@0 314 }
michael@0 315 return nullptr;
michael@0 316 }
michael@0 317
michael@0 318 static inline int IsWhiteSpace(int c) {
michael@0 319 return (c == ' ') || (c == '\t') || (c == '\n') || (c == '\r');
michael@0 320 }
michael@0 321
michael@0 322 static bool EatWS(FILE* aFile)
michael@0 323 {
michael@0 324 for (;;) {
michael@0 325 int c = getc(aFile);
michael@0 326 if (c < 0) {
michael@0 327 return false;
michael@0 328 }
michael@0 329 if (!IsWhiteSpace(c)) {
michael@0 330 ungetc(c, aFile);
michael@0 331 break;
michael@0 332 }
michael@0 333 }
michael@0 334 return true;
michael@0 335 }
michael@0 336
michael@0 337 static bool Expect(FILE* aFile, char aChar)
michael@0 338 {
michael@0 339 int c = getc(aFile);
michael@0 340 if (c < 0) return false;
michael@0 341 if (c != aChar) {
michael@0 342 ungetc(c, aFile);
michael@0 343 return false;
michael@0 344 }
michael@0 345 return true;
michael@0 346 }
michael@0 347
michael@0 348 static char* ReadIdent(FILE* aFile)
michael@0 349 {
michael@0 350 char id[1000];
michael@0 351 char* ip = id;
michael@0 352 char* end = ip + sizeof(id) - 1;
michael@0 353 while (ip < end) {
michael@0 354 int c = fgetc(aFile);
michael@0 355 if (c < 0) return nullptr;
michael@0 356 if ((c == '=') || (c == '>') || (c == '/') || IsWhiteSpace(c)) {
michael@0 357 ungetc(c, aFile);
michael@0 358 break;
michael@0 359 }
michael@0 360 *ip++ = char(c);
michael@0 361 }
michael@0 362 *ip = '\0';
michael@0 363 return nsFrameUtil::Copy(id);
michael@0 364 /* may return a null pointer */
michael@0 365 }
michael@0 366
michael@0 367 static char* ReadString(FILE* aFile)
michael@0 368 {
michael@0 369 if (!Expect(aFile, '\"')) {
michael@0 370 return nullptr;
michael@0 371 }
michael@0 372 char id[1000];
michael@0 373 char* ip = id;
michael@0 374 char* end = ip + sizeof(id) - 1;
michael@0 375 while (ip < end) {
michael@0 376 int c = fgetc(aFile);
michael@0 377 if (c < 0) return nullptr;
michael@0 378 if (c == '\"') {
michael@0 379 break;
michael@0 380 }
michael@0 381 *ip++ = char(c);
michael@0 382 }
michael@0 383 *ip = '\0';
michael@0 384 return nsFrameUtil::Copy(id);
michael@0 385 /* may return a null pointer */
michael@0 386 }
michael@0 387
michael@0 388 void
michael@0 389 nsFrameUtil::Tag::ReadAttrs(FILE* aFile)
michael@0 390 {
michael@0 391 for (;;) {
michael@0 392 if (!EatWS(aFile)) {
michael@0 393 break;
michael@0 394 }
michael@0 395 int c = getc(aFile);
michael@0 396 if (c < 0) break;
michael@0 397 if (c == '/') {
michael@0 398 if (!EatWS(aFile)) {
michael@0 399 return;
michael@0 400 }
michael@0 401 if (Expect(aFile, '>')) {
michael@0 402 type = openClose;
michael@0 403 break;
michael@0 404 }
michael@0 405 }
michael@0 406 else if (c == '>') {
michael@0 407 break;
michael@0 408 }
michael@0 409 ungetc(c, aFile);
michael@0 410 char* attr = ReadIdent(aFile);
michael@0 411 if ((nullptr == attr) || !EatWS(aFile)) {
michael@0 412 break;
michael@0 413 }
michael@0 414 char* value = nullptr;
michael@0 415 if (Expect(aFile, '=')) {
michael@0 416 value = ReadString(aFile);
michael@0 417 if (nullptr == value) {
michael@0 418 delete [] attr;
michael@0 419 break;
michael@0 420 }
michael@0 421 }
michael@0 422 AddAttr(attr, value);
michael@0 423 }
michael@0 424 }
michael@0 425
michael@0 426 nsFrameUtil::Tag*
michael@0 427 nsFrameUtil::Tag::Parse(FILE* aFile)
michael@0 428 {
michael@0 429 if (!EatWS(aFile)) {
michael@0 430 return nullptr;
michael@0 431 }
michael@0 432 if (Expect(aFile, '<')) {
michael@0 433 Tag* tag = new Tag;
michael@0 434 if (Expect(aFile, '/')) {
michael@0 435 tag->type = close;
michael@0 436 }
michael@0 437 else {
michael@0 438 tag->type = open;
michael@0 439 }
michael@0 440 tag->name = ReadIdent(aFile);
michael@0 441 tag->ReadAttrs(aFile);
michael@0 442 return tag;
michael@0 443 }
michael@0 444 return nullptr;
michael@0 445 }
michael@0 446
michael@0 447 void
michael@0 448 nsFrameUtil::Tag::ToString(nsString& aResult)
michael@0 449 {
michael@0 450 aResult.Truncate();
michael@0 451 aResult.Append(char16_t('<'));
michael@0 452 if (type == close) {
michael@0 453 aResult.Append(char16_t('/'));
michael@0 454 }
michael@0 455 aResult.AppendASCII(name);
michael@0 456 if (0 != num) {
michael@0 457 int32_t i, n = num;
michael@0 458 for (i = 0; i < n; i++) {
michael@0 459 aResult.Append(char16_t(' '));
michael@0 460 aResult.AppendASCII(attributes[i]);
michael@0 461 if (values[i]) {
michael@0 462 aResult.AppendLiteral("=\"");
michael@0 463 aResult.AppendASCII(values[i]);
michael@0 464 aResult.Append(char16_t('\"'));
michael@0 465 }
michael@0 466 }
michael@0 467 }
michael@0 468 if (type == openClose) {
michael@0 469 aResult.Append(char16_t('/'));
michael@0 470 }
michael@0 471 aResult.Append(char16_t('>'));
michael@0 472 }
michael@0 473
michael@0 474 //----------------------------------------------------------------------
michael@0 475
michael@0 476 nsresult
michael@0 477 NS_NewFrameUtil(nsIFrameUtil** aResult)
michael@0 478 {
michael@0 479 NS_PRECONDITION(nullptr != aResult, "null pointer");
michael@0 480 if (nullptr == aResult) {
michael@0 481 return NS_ERROR_NULL_POINTER;
michael@0 482 }
michael@0 483
michael@0 484 nsFrameUtil* it = new nsFrameUtil();
michael@0 485
michael@0 486 NS_ADDREF(*aResult = it);
michael@0 487 return NS_OK;
michael@0 488 }
michael@0 489
michael@0 490 nsFrameUtil::nsFrameUtil()
michael@0 491 {
michael@0 492 }
michael@0 493
michael@0 494 nsFrameUtil::~nsFrameUtil()
michael@0 495 {
michael@0 496 }
michael@0 497
michael@0 498 NS_IMPL_ISUPPORTS(nsFrameUtil, nsIFrameUtil)
michael@0 499
michael@0 500 void
michael@0 501 nsFrameUtil::DumpNode(Node* aNode, FILE* aOutputFile, int32_t aIndent)
michael@0 502 {
michael@0 503 nsFrame::IndentBy(aOutputFile, aIndent);
michael@0 504 fprintf(aOutputFile, "%s 0x%x %d,%d,%d,%d, %s\n", aNode->type, aNode->state,
michael@0 505 aNode->bbox.x, aNode->bbox.y,
michael@0 506 aNode->bbox.width, aNode->bbox.height,
michael@0 507 aNode->styleData.get());
michael@0 508 }
michael@0 509
michael@0 510 void
michael@0 511 nsFrameUtil::DumpTree(Node* aNode, FILE* aOutputFile, int32_t aIndent)
michael@0 512 {
michael@0 513 while (nullptr != aNode) {
michael@0 514 DumpNode(aNode, aOutputFile, aIndent);
michael@0 515 nsFrameUtil::NodeList* lists = aNode->lists;
michael@0 516 if (nullptr != lists) {
michael@0 517 while (nullptr != lists) {
michael@0 518 nsFrame::IndentBy(aOutputFile, aIndent);
michael@0 519 fprintf(aOutputFile, " list: %s\n",
michael@0 520 lists->name ? lists->name : "primary");
michael@0 521 DumpTree(lists->node, aOutputFile, aIndent + 1);
michael@0 522 lists = lists->next;
michael@0 523 }
michael@0 524 }
michael@0 525 aNode = aNode->next;
michael@0 526 }
michael@0 527 }
michael@0 528
michael@0 529 bool
michael@0 530 nsFrameUtil::CompareTrees(Node* tree1, Node* tree2)
michael@0 531 {
michael@0 532 bool result = true;
michael@0 533 for (;; tree1 = tree1->next, tree2 = tree2->next) {
michael@0 534 // Make sure both nodes are non-null, or at least agree with each other
michael@0 535 if (nullptr == tree1) {
michael@0 536 if (nullptr == tree2) {
michael@0 537 break;
michael@0 538 }
michael@0 539 printf("first tree prematurely ends\n");
michael@0 540 return false;
michael@0 541 }
michael@0 542 else if (nullptr == tree2) {
michael@0 543 printf("second tree prematurely ends\n");
michael@0 544 return false;
michael@0 545 }
michael@0 546
michael@0 547 // Check the attributes that we care about
michael@0 548 if (0 != PL_strcmp(tree1->type, tree2->type)) {
michael@0 549 printf("frame type mismatch: %s vs. %s\n", tree1->type, tree2->type);
michael@0 550 printf("Node 1:\n");
michael@0 551 DumpNode(tree1, stdout, 1);
michael@0 552 printf("Node 2:\n");
michael@0 553 DumpNode(tree2, stdout, 1);
michael@0 554 return false;
michael@0 555 }
michael@0 556
michael@0 557 // Ignore the XUL scrollbar frames
michael@0 558 static const char kScrollbarFrame[] = "ScrollbarFrame";
michael@0 559 if (0 == PL_strncmp(tree1->type, kScrollbarFrame, sizeof(kScrollbarFrame) - 1))
michael@0 560 continue;
michael@0 561
michael@0 562 if (tree1->state != tree2->state) {
michael@0 563 printf("frame state mismatch: 0x%x vs. 0x%x\n",
michael@0 564 tree1->state, tree2->state);
michael@0 565 printf("Node 1:\n");
michael@0 566 DumpNode(tree1, stdout, 1);
michael@0 567 printf("Node 2:\n");
michael@0 568 DumpNode(tree2, stdout, 1);
michael@0 569 result = false; // we have a non-critical failure, so remember that but continue
michael@0 570 }
michael@0 571 if (tree1->bbox.IsEqualInterior(tree2->bbox)) {
michael@0 572 printf("frame bbox mismatch: %d,%d,%d,%d vs. %d,%d,%d,%d\n",
michael@0 573 tree1->bbox.x, tree1->bbox.y,
michael@0 574 tree1->bbox.width, tree1->bbox.height,
michael@0 575 tree2->bbox.x, tree2->bbox.y,
michael@0 576 tree2->bbox.width, tree2->bbox.height);
michael@0 577 printf("Node 1:\n");
michael@0 578 DumpNode(tree1, stdout, 1);
michael@0 579 printf("Node 2:\n");
michael@0 580 DumpNode(tree2, stdout, 1);
michael@0 581 result = false; // we have a non-critical failure, so remember that but continue
michael@0 582 }
michael@0 583 if (tree1->styleData != tree2->styleData) {
michael@0 584 printf("frame style data mismatch: %s vs. %s\n",
michael@0 585 tree1->styleData.get(),
michael@0 586 tree2->styleData.get());
michael@0 587 }
michael@0 588
michael@0 589 // Check child lists too
michael@0 590 NodeList* list1 = tree1->lists;
michael@0 591 NodeList* list2 = tree2->lists;
michael@0 592 for (;;) {
michael@0 593 if (nullptr == list1) {
michael@0 594 if (nullptr != list2) {
michael@0 595 printf("first tree prematurely ends (no child lists)\n");
michael@0 596 printf("Node 1:\n");
michael@0 597 DumpNode(tree1, stdout, 1);
michael@0 598 printf("Node 2:\n");
michael@0 599 DumpNode(tree2, stdout, 1);
michael@0 600 return false;
michael@0 601 }
michael@0 602 else {
michael@0 603 break;
michael@0 604 }
michael@0 605 }
michael@0 606 if (nullptr == list2) {
michael@0 607 printf("second tree prematurely ends (no child lists)\n");
michael@0 608 printf("Node 1:\n");
michael@0 609 DumpNode(tree1, stdout, 1);
michael@0 610 printf("Node 2:\n");
michael@0 611 DumpNode(tree2, stdout, 1);
michael@0 612 return false;
michael@0 613 }
michael@0 614 if (0 != PL_strcmp(list1->name, list2->name)) {
michael@0 615 printf("child-list name mismatch: %s vs. %s\n",
michael@0 616 list1->name ? list1->name : "(null)",
michael@0 617 list2->name ? list2->name : "(null)");
michael@0 618 result = false; // we have a non-critical failure, so remember that but continue
michael@0 619 }
michael@0 620 else {
michael@0 621 bool equiv = CompareTrees(list1->node, list2->node);
michael@0 622 if (!equiv) {
michael@0 623 return equiv;
michael@0 624 }
michael@0 625 }
michael@0 626 list1 = list1->next;
michael@0 627 list2 = list2->next;
michael@0 628 }
michael@0 629 }
michael@0 630 return result;
michael@0 631 }
michael@0 632
michael@0 633 NS_IMETHODIMP
michael@0 634 nsFrameUtil::CompareRegressionData(FILE* aFile1, FILE* aFile2,int32_t aRegressionOutput)
michael@0 635 {
michael@0 636 Node* tree1 = Node::ReadTree(aFile1);
michael@0 637 Node* tree2 = Node::ReadTree(aFile2);
michael@0 638
michael@0 639 nsresult rv = NS_OK;
michael@0 640 if (!CompareTrees(tree1, tree2)) {
michael@0 641 // only output this if aRegressionOutput is 0
michael@0 642 if( 0 == aRegressionOutput ){
michael@0 643 printf("Regression data 1:\n");
michael@0 644 DumpTree(tree1, stdout, 0);
michael@0 645 printf("Regression data 2:\n");
michael@0 646 DumpTree(tree2, stdout, 0);
michael@0 647 }
michael@0 648 rv = NS_ERROR_FAILURE;
michael@0 649 }
michael@0 650
michael@0 651 Node::Destroy(tree1);
michael@0 652 Node::Destroy(tree2);
michael@0 653
michael@0 654 return rv;
michael@0 655 }
michael@0 656
michael@0 657 NS_IMETHODIMP
michael@0 658 nsFrameUtil::DumpRegressionData(FILE* aInputFile, FILE* aOutputFile)
michael@0 659 {
michael@0 660 Node* tree1 = Node::ReadTree(aInputFile);
michael@0 661 if (nullptr != tree1) {
michael@0 662 DumpTree(tree1, aOutputFile, 0);
michael@0 663 Node::Destroy(tree1);
michael@0 664 return NS_OK;
michael@0 665 }
michael@0 666 return NS_ERROR_FAILURE;
michael@0 667 }
michael@0 668 #endif

mercurial