| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "core/editing/EditingUtilities.h" | 5 #include "core/editing/EditingUtilities.h" |
| 6 | 6 |
| 7 #include "core/dom/StaticNodeList.h" | 7 #include "core/dom/StaticNodeList.h" |
| 8 #include "core/editing/EditingTestBase.h" | 8 #include "core/editing/EditingTestBase.h" |
| 9 | 9 |
| 10 namespace blink { | 10 namespace blink { |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 193 << "Can't merge a element with no attributes and another element with an
attribute."; | 193 << "Can't merge a element with no attributes and another element with an
attribute."; |
| 194 | 194 |
| 195 // We can't use contenteditable attribute to make editability difference | 195 // We can't use contenteditable attribute to make editability difference |
| 196 // because the hasEquivalentAttributes check is done earier. | 196 // because the hasEquivalentAttributes check is done earier. |
| 197 EXPECT_FALSE(areIdenticalElements(*items->item(0), *items->item(1))) | 197 EXPECT_FALSE(areIdenticalElements(*items->item(0), *items->item(1))) |
| 198 << "Can't merge non-editable nodes."; | 198 << "Can't merge non-editable nodes."; |
| 199 | 199 |
| 200 EXPECT_TRUE(areIdenticalElements(*items->item(1), *items->item(3))); | 200 EXPECT_TRUE(areIdenticalElements(*items->item(1), *items->item(3))); |
| 201 } | 201 } |
| 202 | 202 |
| 203 TEST_F(EditingUtilitiesTest, uncheckedPreviousNextOffset_FirstLetter) |
| 204 { |
| 205 setBodyContent("<style>p::first-letter {color:red;}</style><p id='target'>ab
c</p>"); |
| 206 Node* node = document().getElementById("target")->firstChild(); |
| 207 EXPECT_EQ(2, uncheckedPreviousOffset(node, 3)); |
| 208 EXPECT_EQ(1, uncheckedPreviousOffset(node, 2)); |
| 209 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 210 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 211 EXPECT_EQ(2, uncheckedNextOffset(node, 1)); |
| 212 EXPECT_EQ(3, uncheckedNextOffset(node, 2)); |
| 213 |
| 214 updateLayoutAndStyleForPainting(); |
| 215 EXPECT_NE(nullptr, node->layoutObject()); |
| 216 EXPECT_EQ(2, uncheckedPreviousOffset(node, 3)); |
| 217 EXPECT_EQ(1, uncheckedPreviousOffset(node, 2)); |
| 218 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 219 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 220 EXPECT_EQ(2, uncheckedNextOffset(node, 1)); |
| 221 EXPECT_EQ(3, uncheckedNextOffset(node, 2)); |
| 222 } |
| 223 |
| 224 TEST_F(EditingUtilitiesTest, uncheckedPreviousNextOffset_textTransform) |
| 225 { |
| 226 setBodyContent("<style>p {text-transform:uppercase}</style><p id='target'>ab
c</p>"); |
| 227 Node* node = document().getElementById("target")->firstChild(); |
| 228 EXPECT_EQ(2, uncheckedPreviousOffset(node, 3)); |
| 229 EXPECT_EQ(1, uncheckedPreviousOffset(node, 2)); |
| 230 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 231 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 232 EXPECT_EQ(2, uncheckedNextOffset(node, 1)); |
| 233 EXPECT_EQ(3, uncheckedNextOffset(node, 2)); |
| 234 |
| 235 updateLayoutAndStyleForPainting(); |
| 236 EXPECT_NE(nullptr, node->layoutObject()); |
| 237 EXPECT_EQ(2, uncheckedPreviousOffset(node, 3)); |
| 238 EXPECT_EQ(1, uncheckedPreviousOffset(node, 2)); |
| 239 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 240 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 241 EXPECT_EQ(2, uncheckedNextOffset(node, 1)); |
| 242 EXPECT_EQ(3, uncheckedNextOffset(node, 2)); |
| 243 } |
| 244 |
| 245 // Following breaking rules come from http://unicode.org/reports/tr29/ |
| 246 // Note that some of rules are in draft. Also see |
| 247 // http://www.unicode.org/reports/tr29/proposed.html |
| 248 TEST_F(EditingUtilitiesTest, uncheckedPreviousNextOffset) |
| 249 { |
| 250 // GB1: Break at the start of text. |
| 251 setBodyContent("<p id='target'>a</p>"); |
| 252 Node* node = document().getElementById("target")->firstChild(); |
| 253 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 254 |
| 255 // GB2: Break at the end of text. |
| 256 setBodyContent("<p id='target'>a</p>"); |
| 257 node = document().getElementById("target")->firstChild(); |
| 258 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 259 |
| 260 // GB3: Do not break between CR and LF. |
| 261 setBodyContent("<p id='target'>a
b</p>"); |
| 262 node = document().getElementById("target")->firstChild(); |
| 263 EXPECT_EQ(3, uncheckedPreviousOffset(node, 4)); |
| 264 // TODO(nona) : Enable following expectation. |
| 265 // EXPECT_EQ(1, uncheckedPreviousOffset(node, 3)); |
| 266 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 267 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 268 // TODO(nona) : Enable following expectation. |
| 269 // EXPECT_EQ(3, uncheckedNextOffset(node, 1)); |
| 270 EXPECT_EQ(4, uncheckedNextOffset(node, 3)); |
| 271 |
| 272 // GB4,GB5: Break before and after CR/LF/Control. |
| 273 setBodyContent("<p id='target'>a
b</p>"); // CR |
| 274 node = document().getElementById("target")->firstChild(); |
| 275 EXPECT_EQ(2, uncheckedPreviousOffset(node, 3)); |
| 276 EXPECT_EQ(1, uncheckedPreviousOffset(node, 2)); |
| 277 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 278 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 279 EXPECT_EQ(2, uncheckedNextOffset(node, 1)); |
| 280 EXPECT_EQ(3, uncheckedNextOffset(node, 2)); |
| 281 setBodyContent("<p id='target'>a
b</p>"); // LF |
| 282 node = document().getElementById("target")->firstChild(); |
| 283 EXPECT_EQ(2, uncheckedPreviousOffset(node, 3)); |
| 284 EXPECT_EQ(1, uncheckedPreviousOffset(node, 2)); |
| 285 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 286 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 287 EXPECT_EQ(2, uncheckedNextOffset(node, 1)); |
| 288 EXPECT_EQ(3, uncheckedNextOffset(node, 2)); |
| 289 setBodyContent("<p id='target'>a­b</p>"); // U+00AD(SOFT HYPHEN) has Co
ntrol property. |
| 290 node = document().getElementById("target")->firstChild(); |
| 291 EXPECT_EQ(2, uncheckedPreviousOffset(node, 3)); |
| 292 EXPECT_EQ(1, uncheckedPreviousOffset(node, 2)); |
| 293 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 294 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 295 EXPECT_EQ(2, uncheckedNextOffset(node, 1)); |
| 296 EXPECT_EQ(3, uncheckedNextOffset(node, 2)); |
| 297 |
| 298 // GB6: Don't break Hangul sequence. |
| 299 const std::string L = "ᄀ"; // U+1100 (HANGUL CHOSEONG KIYEOK) has L p
roperty. |
| 300 const std::string V = "ᅠ"; // U+1160 (HANGUL JUNGSEONG FILLER) has V
property. |
| 301 const std::string LV = "가"; // U+AC00 (HANGUL SYLLABLE GA) has LV pro
perty. |
| 302 const std::string LVT = "각"; // U+AC01 (HANGUL SYLLABLE GAG) has LVT
property. |
| 303 const std::string T = "ᆨ"; // U+11A8 (HANGUL JONGSEONG KIYEOK) has T
property. |
| 304 setBodyContent("<p id='target'>a" + L + L + "b</p>"); // L x L |
| 305 node = document().getElementById("target")->firstChild(); |
| 306 EXPECT_EQ(3, uncheckedPreviousOffset(node, 4)); |
| 307 EXPECT_EQ(1, uncheckedPreviousOffset(node, 3)); |
| 308 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 309 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 310 EXPECT_EQ(3, uncheckedNextOffset(node, 1)); |
| 311 EXPECT_EQ(4, uncheckedNextOffset(node, 3)); |
| 312 setBodyContent("<p id='target'>a" + L + V +"b</p>"); // L x V |
| 313 node = document().getElementById("target")->firstChild(); |
| 314 EXPECT_EQ(3, uncheckedPreviousOffset(node, 4)); |
| 315 EXPECT_EQ(1, uncheckedPreviousOffset(node, 3)); |
| 316 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 317 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 318 EXPECT_EQ(3, uncheckedNextOffset(node, 1)); |
| 319 EXPECT_EQ(4, uncheckedNextOffset(node, 3)); |
| 320 setBodyContent("<p id='target'>a" + L + LV + "b</p>"); // L x LV |
| 321 node = document().getElementById("target")->firstChild(); |
| 322 EXPECT_EQ(3, uncheckedPreviousOffset(node, 4)); |
| 323 EXPECT_EQ(1, uncheckedPreviousOffset(node, 3)); |
| 324 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 325 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 326 EXPECT_EQ(3, uncheckedNextOffset(node, 1)); |
| 327 EXPECT_EQ(4, uncheckedNextOffset(node, 3)); |
| 328 setBodyContent("<p id='target'>a" + L + LVT + "b</p>"); // L x LVT |
| 329 node = document().getElementById("target")->firstChild(); |
| 330 EXPECT_EQ(3, uncheckedPreviousOffset(node, 4)); |
| 331 EXPECT_EQ(1, uncheckedPreviousOffset(node, 3)); |
| 332 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 333 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 334 EXPECT_EQ(3, uncheckedNextOffset(node, 1)); |
| 335 EXPECT_EQ(4, uncheckedNextOffset(node, 3)); |
| 336 |
| 337 // GB7: Don't break Hangul sequence. |
| 338 setBodyContent("<p id='target'>a" + LV + V + "b</p>"); // LV x V |
| 339 node = document().getElementById("target")->firstChild(); |
| 340 EXPECT_EQ(3, uncheckedPreviousOffset(node, 4)); |
| 341 EXPECT_EQ(1, uncheckedPreviousOffset(node, 3)); |
| 342 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 343 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 344 EXPECT_EQ(3, uncheckedNextOffset(node, 1)); |
| 345 EXPECT_EQ(4, uncheckedNextOffset(node, 3)); |
| 346 setBodyContent("<p id='target'>a" + LV + T + "b</p>"); // LV x T |
| 347 node = document().getElementById("target")->firstChild(); |
| 348 EXPECT_EQ(3, uncheckedPreviousOffset(node, 4)); |
| 349 EXPECT_EQ(1, uncheckedPreviousOffset(node, 3)); |
| 350 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 351 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 352 EXPECT_EQ(3, uncheckedNextOffset(node, 1)); |
| 353 EXPECT_EQ(4, uncheckedNextOffset(node, 3)); |
| 354 setBodyContent("<p id='target'>a" + V + V + "b</p>"); // V x V |
| 355 node = document().getElementById("target")->firstChild(); |
| 356 EXPECT_EQ(3, uncheckedPreviousOffset(node, 4)); |
| 357 EXPECT_EQ(1, uncheckedPreviousOffset(node, 3)); |
| 358 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 359 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 360 EXPECT_EQ(3, uncheckedNextOffset(node, 1)); |
| 361 EXPECT_EQ(4, uncheckedNextOffset(node, 3)); |
| 362 setBodyContent("<p id='target'>a" + V + T + "b</p>"); // V x T |
| 363 node = document().getElementById("target")->firstChild(); |
| 364 EXPECT_EQ(3, uncheckedPreviousOffset(node, 4)); |
| 365 EXPECT_EQ(1, uncheckedPreviousOffset(node, 3)); |
| 366 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 367 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 368 EXPECT_EQ(3, uncheckedNextOffset(node, 1)); |
| 369 EXPECT_EQ(4, uncheckedNextOffset(node, 3)); |
| 370 |
| 371 // GB8: Don't break Hangul sequence. |
| 372 setBodyContent("<p id='target'>a" + LVT + T + "b</p>"); // LVT x T |
| 373 node = document().getElementById("target")->firstChild(); |
| 374 EXPECT_EQ(3, uncheckedPreviousOffset(node, 4)); |
| 375 EXPECT_EQ(1, uncheckedPreviousOffset(node, 3)); |
| 376 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 377 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 378 EXPECT_EQ(3, uncheckedNextOffset(node, 1)); |
| 379 EXPECT_EQ(4, uncheckedNextOffset(node, 3)); |
| 380 setBodyContent("<p id='target'>a" + T + T + "b</p>"); // T x T |
| 381 node = document().getElementById("target")->firstChild(); |
| 382 EXPECT_EQ(3, uncheckedPreviousOffset(node, 4)); |
| 383 EXPECT_EQ(1, uncheckedPreviousOffset(node, 3)); |
| 384 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 385 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 386 EXPECT_EQ(3, uncheckedNextOffset(node, 1)); |
| 387 EXPECT_EQ(4, uncheckedNextOffset(node, 3)); |
| 388 |
| 389 // Break other Hangul syllable combination. See test of GB999. |
| 390 |
| 391 // GB8a: Don't break between regional indicator if there are even numbered r
egional indicator symbols before. |
| 392 // U+1F1FA is REGIONAL INDICATOR SYMBOL LETTER U. |
| 393 // U+1F1F8 is REGIONAL INDICATOR SYMBOL LETTER S. |
| 394 const std::string flag = "🇺🇸"; // US flag. |
| 395 setBodyContent("<p id='target'>" + flag + flag + flag + flag + "a</p>"); //
^(RI RI)* RI x RI |
| 396 node = document().getElementById("target")->firstChild(); |
| 397 EXPECT_EQ(16, uncheckedPreviousOffset(node, 17)); |
| 398 EXPECT_EQ(12, uncheckedPreviousOffset(node, 16)); |
| 399 // TODO(nona): Enable following expectations. |
| 400 // EXPECT_EQ(8, uncheckedPreviousOffset(node, 12)); |
| 401 // EXPECT_EQ(4, uncheckedPreviousOffset(node, 8)); |
| 402 // EXPECT_EQ(0, uncheckedPreviousOffset(node, 4)); |
| 403 // EXPECT_EQ(4, uncheckedNextOffset(node, 0)); |
| 404 // EXPECT_EQ(8, uncheckedNextOffset(node, 4)); |
| 405 EXPECT_EQ(12, uncheckedNextOffset(node, 8)); |
| 406 EXPECT_EQ(16, uncheckedNextOffset(node, 12)); |
| 407 EXPECT_EQ(17, uncheckedNextOffset(node, 16)); |
| 408 |
| 409 // GB8c: Don't break between regional indicator if there are even numbered r
egional indicator symbols before. |
| 410 setBodyContent("<p id='target'>a" + flag + flag + flag + flag + "b</p>"); //
[^RI] (RI RI)* RI x RI |
| 411 node = document().getElementById("target")->firstChild(); |
| 412 EXPECT_EQ(17, uncheckedPreviousOffset(node, 18)); |
| 413 EXPECT_EQ(13, uncheckedPreviousOffset(node, 17)); |
| 414 // TODO(nona): Enable following expectations. |
| 415 // EXPECT_EQ(9, uncheckedPreviousOffset(node, 13)); |
| 416 // EXPECT_EQ(5, uncheckedPreviousOffset(node, 9)); |
| 417 EXPECT_EQ(1, uncheckedPreviousOffset(node, 5)); |
| 418 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 419 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 420 // TODO(nona): Enable following expectations. |
| 421 // EXPECT_EQ(5, uncheckedNextOffset(node, 1)); |
| 422 // EXPECT_EQ(9, uncheckedNextOffset(node, 5)); |
| 423 EXPECT_EQ(13, uncheckedNextOffset(node, 9)); |
| 424 EXPECT_EQ(17, uncheckedNextOffset(node, 13)); |
| 425 EXPECT_EQ(18, uncheckedNextOffset(node, 17)); |
| 426 |
| 427 // GB8c: Break if there is an odd number of regional indicator symbols befor
e. |
| 428 setBodyContent("<p id='target'>a" + flag + flag + flag + flag + "🇸b<
/p>"); // RI รท RI |
| 429 node = document().getElementById("target")->firstChild(); |
| 430 EXPECT_EQ(19, uncheckedPreviousOffset(node, 20)); |
| 431 // TODO(nona): Enable following expectations. |
| 432 // EXPECT_EQ(17, uncheckedPreviousOffset(node, 19)); |
| 433 // EXPECT_EQ(13, uncheckedPreviousOffset(node, 17)); |
| 434 // EXPECT_EQ(9, uncheckedPreviousOffset(node, 13)); |
| 435 // EXPECT_EQ(5, uncheckedPreviousOffset(node, 9)); |
| 436 EXPECT_EQ(1, uncheckedPreviousOffset(node, 5)); |
| 437 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 438 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 439 // TODO(nona): Enable following expectations. |
| 440 // EXPECT_EQ(5, uncheckedNextOffset(node, 1)); |
| 441 // EXPECT_EQ(9, uncheckedNextOffset(node, 5)); |
| 442 // EXPECT_EQ(13, uncheckedNextOffset(node, 9)); |
| 443 EXPECT_EQ(17, uncheckedNextOffset(node, 13)); |
| 444 EXPECT_EQ(19, uncheckedNextOffset(node, 17)); |
| 445 EXPECT_EQ(20, uncheckedNextOffset(node, 19)); |
| 446 |
| 447 // GB9: Do not break before extending characters or ZWJ. |
| 448 // U+0300(COMBINING GRAVE ACCENT) has Extend property. |
| 449 setBodyContent("<p id='target'>àb</p>"); // x Extend |
| 450 node = document().getElementById("target")->firstChild(); |
| 451 EXPECT_EQ(2, uncheckedPreviousOffset(node, 3)); |
| 452 EXPECT_EQ(0, uncheckedPreviousOffset(node, 2)); |
| 453 EXPECT_EQ(2, uncheckedNextOffset(node, 0)); |
| 454 EXPECT_EQ(3, uncheckedNextOffset(node, 2)); |
| 455 // U+200D is ZERO WIDTH JOINER. |
| 456 setBodyContent("<p id='target'>a‍b</p>"); // x ZWJ |
| 457 node = document().getElementById("target")->firstChild(); |
| 458 EXPECT_EQ(2, uncheckedPreviousOffset(node, 3)); |
| 459 EXPECT_EQ(0, uncheckedPreviousOffset(node, 2)); |
| 460 EXPECT_EQ(2, uncheckedNextOffset(node, 0)); |
| 461 EXPECT_EQ(3, uncheckedNextOffset(node, 2)); |
| 462 |
| 463 // GB9a: Do not break before SpacingMarks. |
| 464 // U+0903(DEVANAGARI SIGN VISARGA) has SpacingMark property. |
| 465 setBodyContent("<p id='target'>aःb</p>"); // x SpacingMark |
| 466 node = document().getElementById("target")->firstChild(); |
| 467 EXPECT_EQ(2, uncheckedPreviousOffset(node, 3)); |
| 468 EXPECT_EQ(0, uncheckedPreviousOffset(node, 2)); |
| 469 EXPECT_EQ(2, uncheckedNextOffset(node, 0)); |
| 470 EXPECT_EQ(3, uncheckedNextOffset(node, 2)); |
| 471 |
| 472 // GB9b: Do not break after Prepend but Blink breaks after Prepend char to a
ddress Bug 24342. |
| 473 // U+0600(ARABIC NUMBER SIGN) has Prepend property. |
| 474 setBodyContent("<p id='target'>a؀b</p>"); // Prepend x |
| 475 node = document().getElementById("target")->firstChild(); |
| 476 EXPECT_EQ(2, uncheckedPreviousOffset(node, 3)); |
| 477 EXPECT_EQ(1, uncheckedPreviousOffset(node, 2)); |
| 478 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 479 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 480 EXPECT_EQ(2, uncheckedNextOffset(node, 1)); |
| 481 EXPECT_EQ(3, uncheckedNextOffset(node, 2)); |
| 482 |
| 483 // Blink customization: Don't break before Japanese half-width katakana voic
ed marks. |
| 484 setBodyContent("<p id='target'>aガb</p>"); |
| 485 node = document().getElementById("target")->firstChild(); |
| 486 EXPECT_EQ(3, uncheckedPreviousOffset(node, 4)); |
| 487 EXPECT_EQ(1, uncheckedPreviousOffset(node, 3)); |
| 488 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 489 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 490 EXPECT_EQ(3, uncheckedNextOffset(node, 1)); |
| 491 EXPECT_EQ(4, uncheckedNextOffset(node, 3)); |
| 492 |
| 493 // Additional rule for Virama: Do not break after Virama except for Tamil. |
| 494 // See http://www.unicode.org/Public/9.0.0/ucd/IndicSyllabicCategory-9.0.0d2
.txt |
| 495 // U+0905 is DEVANAGARI LETTER A. This has Extend property. |
| 496 // U+094D is DEVANAGARI SIGN VIRAMA. This has Virama property. |
| 497 // U+0915 is DEVANAGARI LETTER KA. |
| 498 setBodyContent("<p id='target'>aअ्कb</p>"); |
| 499 node = document().getElementById("target")->firstChild(); |
| 500 EXPECT_EQ(4, uncheckedPreviousOffset(node, 5)); |
| 501 EXPECT_EQ(1, uncheckedPreviousOffset(node, 4)); |
| 502 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 503 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 504 EXPECT_EQ(4, uncheckedNextOffset(node, 1)); |
| 505 EXPECT_EQ(5, uncheckedNextOffset(node, 4)); |
| 506 // U+0B85 is TAMIL LETTER A. This has Extend property. |
| 507 // U+0BCD is TAMIL SIGN VIRAMA. This has Virama property. |
| 508 // U+0B95 is TAMIL LETTER KA. |
| 509 setBodyContent("<p id='target'>aஅ்கb</p>"); |
| 510 node = document().getElementById("target")->firstChild(); |
| 511 EXPECT_EQ(4, uncheckedPreviousOffset(node, 5)); |
| 512 EXPECT_EQ(3, uncheckedPreviousOffset(node, 4)); |
| 513 EXPECT_EQ(1, uncheckedPreviousOffset(node, 3)); |
| 514 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 515 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 516 EXPECT_EQ(3, uncheckedNextOffset(node, 1)); |
| 517 EXPECT_EQ(4, uncheckedNextOffset(node, 3)); |
| 518 EXPECT_EQ(5, uncheckedNextOffset(node, 4)); |
| 519 // TODO(nona): Consider to add Sinhala, Balinese, etc. |
| 520 |
| 521 // GB10: Do not break within emoji modifier. |
| 522 // U+1F385(FATHER CHRISTMAS) has E_Base property. |
| 523 // U+1F3FB(EMOJI MODIFIER FITZPATRICK TYPE-1-2) has E_Modifier property. |
| 524 setBodyContent("<p id='target'>a🎅🏻b</p>"); // E_Base x E_Mod
ifier |
| 525 node = document().getElementById("target")->firstChild(); |
| 526 EXPECT_EQ(5, uncheckedPreviousOffset(node, 6)); |
| 527 // TODO(nona): Enable following expectation. |
| 528 // EXPECT_EQ(1, uncheckedPreviousOffset(node, 5)); |
| 529 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 530 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 531 // TODO(nona): Enable following expectation. |
| 532 // EXPECT_EQ(5, uncheckedNextOffset(node, 1)); |
| 533 EXPECT_EQ(6, uncheckedNextOffset(node, 5)); |
| 534 // U+1F466(BOY) has EBG property. |
| 535 setBodyContent("<p id='target'>a👦🏻b</p>"); // EBG x E_Modifi
er |
| 536 node = document().getElementById("target")->firstChild(); |
| 537 EXPECT_EQ(5, uncheckedPreviousOffset(node, 6)); |
| 538 // TODO(nona): Enable following expectation. |
| 539 // EXPECT_EQ(1, uncheckedPreviousOffset(node, 5)); |
| 540 EXPECT_EQ(0, uncheckedPreviousOffset(node, 1)); |
| 541 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 542 // TODO(nona): Enable following expectation. |
| 543 // EXPECT_EQ(5, uncheckedNextOffset(node, 1)); |
| 544 EXPECT_EQ(6, uncheckedNextOffset(node, 5)); |
| 545 |
| 546 // GB11: Do not break within ZWJ emoji sequence. |
| 547 // U+2764(HEAVY BLACK HEART) has Glue_After_Zwj property. |
| 548 setBodyContent("<p id='target'>a‍❤b</p>"); // ZWJ x Glue_After
_Zwj |
| 549 node = document().getElementById("target")->firstChild(); |
| 550 EXPECT_EQ(3, uncheckedPreviousOffset(node, 4)); |
| 551 // TODO(nona): Enable following expectation. |
| 552 // EXPECT_EQ(0, uncheckedPreviousOffset(node, 3)); |
| 553 // EXPECT_EQ(3, uncheckedNextOffset(node, 0)); |
| 554 EXPECT_EQ(4, uncheckedNextOffset(node, 3)); |
| 555 setBodyContent("<p id='target'>a‍👦b</p>"); // ZWJ x EBG |
| 556 node = document().getElementById("target")->firstChild(); |
| 557 EXPECT_EQ(4, uncheckedPreviousOffset(node, 5)); |
| 558 // TODO(nona): Enable following expectation. |
| 559 // EXPECT_EQ(0, uncheckedPreviousOffset(node, 4)); |
| 560 // EXPECT_EQ(4, uncheckedNextOffset(node, 0)); |
| 561 EXPECT_EQ(5, uncheckedNextOffset(node, 4)); |
| 562 |
| 563 // GB999: Otherwise break everywhere. |
| 564 // Breaks between Hangul syllable except for GB6, GB7, GB8. |
| 565 setBodyContent("<p id='target'>" + L + T + "</p>"); |
| 566 node = document().getElementById("target")->firstChild(); |
| 567 EXPECT_EQ(1, uncheckedPreviousOffset(node, 2)); |
| 568 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 569 setBodyContent("<p id='target'>" + V + L + "</p>"); |
| 570 node = document().getElementById("target")->firstChild(); |
| 571 EXPECT_EQ(1, uncheckedPreviousOffset(node, 2)); |
| 572 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 573 setBodyContent("<p id='target'>" + V + LV + "</p>"); |
| 574 node = document().getElementById("target")->firstChild(); |
| 575 EXPECT_EQ(1, uncheckedPreviousOffset(node, 2)); |
| 576 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 577 setBodyContent("<p id='target'>" + V + LVT + "</p>"); |
| 578 node = document().getElementById("target")->firstChild(); |
| 579 EXPECT_EQ(1, uncheckedPreviousOffset(node, 2)); |
| 580 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 581 setBodyContent("<p id='target'>" + LV + L + "</p>"); |
| 582 node = document().getElementById("target")->firstChild(); |
| 583 EXPECT_EQ(1, uncheckedPreviousOffset(node, 2)); |
| 584 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 585 setBodyContent("<p id='target'>" + LV + LV + "</p>"); |
| 586 node = document().getElementById("target")->firstChild(); |
| 587 EXPECT_EQ(1, uncheckedPreviousOffset(node, 2)); |
| 588 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 589 setBodyContent("<p id='target'>" + LV + LVT + "</p>"); |
| 590 node = document().getElementById("target")->firstChild(); |
| 591 EXPECT_EQ(1, uncheckedPreviousOffset(node, 2)); |
| 592 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 593 setBodyContent("<p id='target'>" + LVT + L + "</p>"); |
| 594 node = document().getElementById("target")->firstChild(); |
| 595 EXPECT_EQ(1, uncheckedPreviousOffset(node, 2)); |
| 596 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 597 setBodyContent("<p id='target'>" + LVT + V + "</p>"); |
| 598 node = document().getElementById("target")->firstChild(); |
| 599 EXPECT_EQ(1, uncheckedPreviousOffset(node, 2)); |
| 600 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 601 setBodyContent("<p id='target'>" + LVT + LV + "</p>"); |
| 602 node = document().getElementById("target")->firstChild(); |
| 603 EXPECT_EQ(1, uncheckedPreviousOffset(node, 2)); |
| 604 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 605 setBodyContent("<p id='target'>" + LVT + LVT + "</p>"); |
| 606 node = document().getElementById("target")->firstChild(); |
| 607 EXPECT_EQ(1, uncheckedPreviousOffset(node, 2)); |
| 608 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 609 setBodyContent("<p id='target'>" + T + L + "</p>"); |
| 610 node = document().getElementById("target")->firstChild(); |
| 611 EXPECT_EQ(1, uncheckedPreviousOffset(node, 2)); |
| 612 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 613 setBodyContent("<p id='target'>" + T + V + "</p>"); |
| 614 node = document().getElementById("target")->firstChild(); |
| 615 EXPECT_EQ(1, uncheckedPreviousOffset(node, 2)); |
| 616 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 617 setBodyContent("<p id='target'>" + T + LV + "</p>"); |
| 618 node = document().getElementById("target")->firstChild(); |
| 619 EXPECT_EQ(1, uncheckedPreviousOffset(node, 2)); |
| 620 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 621 setBodyContent("<p id='target'>" + T + LVT + "</p>"); |
| 622 node = document().getElementById("target")->firstChild(); |
| 623 EXPECT_EQ(1, uncheckedPreviousOffset(node, 2)); |
| 624 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 625 |
| 626 // For GB10, if base emoji character is not E_Base or EBG, break happens bef
ore E_Modifier. |
| 627 setBodyContent("<p id='target'>a🏻</p>"); |
| 628 node = document().getElementById("target")->firstChild(); |
| 629 EXPECT_EQ(1, uncheckedPreviousOffset(node, 3)); |
| 630 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 631 // U+1F5FA(WORLD MAP) doesn't have either E_Base or EBG property. |
| 632 setBodyContent("<p id='target'>🗺🏻</p>"); |
| 633 node = document().getElementById("target")->firstChild(); |
| 634 EXPECT_EQ(2, uncheckedPreviousOffset(node, 4)); |
| 635 EXPECT_EQ(2, uncheckedNextOffset(node, 0)); |
| 636 |
| 637 // For GB11, if trailing character is not Glue_After_Zwj or EBG, break happe
ns after ZWJ. |
| 638 // U+1F5FA(WORLD MAP) doesn't have either Glue_After_Zwj or EBG. |
| 639 setBodyContent("<p id='target'>‍🗺</p>"); |
| 640 node = document().getElementById("target")->firstChild(); |
| 641 EXPECT_EQ(1, uncheckedPreviousOffset(node, 3)); |
| 642 EXPECT_EQ(1, uncheckedNextOffset(node, 0)); |
| 643 } |
| 644 |
| 203 } // namespace blink | 645 } // namespace blink |
| OLD | NEW |