Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cfde_texteditengine_unittest.cpp
Go to the documentation of this file.
1// Copyright 2017 The PDFium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "xfa/fde/cfde_texteditengine.h"
6
7#include "core/fxcrt/fx_codepage.h"
8#include "core/fxcrt/fx_extension.h"
9#include "core/fxge/text_char_pos.h"
10#include "testing/gtest/include/gtest/gtest.h"
11#include "testing/xfa_test_environment.h"
12#include "xfa/fgas/font/cfgas_gefont.h"
13
14namespace pdfium {
15
17 public:
18 class Delegate final : public CFDE_TextEditEngine::Delegate {
19 public:
20 void Reset() {
21 text_is_full = false;
22 fail_validation = false;
23 }
24
25 void NotifyTextFull() override { text_is_full = true; }
26
27 void OnCaretChanged() override {}
28 void OnTextWillChange(CFDE_TextEditEngine::TextChange* change) override {}
29 void OnTextChanged() override {}
30 void OnSelChanged() override {}
31 bool OnValidate(const WideString& wsText) override {
32 return !fail_validation;
33 }
34 void SetScrollOffset(float fScrollOffset) override {}
35
36 bool fail_validation = false;
37 bool text_is_full = false;
38 };
39
42
43 void SetUp() override {
44 const wchar_t kFontFamily[] = L"Arimo Bold";
45 font_ = CFGAS_GEFont::LoadFont(kFontFamily, 0, FX_CodePage::kDefANSI);
46 ASSERT_TRUE(font_);
47
48 engine_ = std::make_unique<CFDE_TextEditEngine>();
49 engine_->SetFont(font_);
50 engine_->SetFontSize(12.0f);
51 }
52
54 engine_.reset();
55 font_.Reset();
56 }
57
58 CFDE_TextEditEngine* engine() const { return engine_.get(); }
59
60 private:
61 RetainPtr<CFGAS_GEFont> font_;
62 std::unique_ptr<CFDE_TextEditEngine> engine_;
63};
64
66 EXPECT_EQ(L"", engine()->GetText());
67
68 engine()->Insert(0, L"");
69 EXPECT_EQ(L"", engine()->GetText());
70 EXPECT_EQ(0U, engine()->GetLength());
71
72 engine()->Insert(0, L"Hello");
73 EXPECT_EQ(L"Hello", engine()->GetText());
74 EXPECT_EQ(5U, engine()->GetLength());
75
76 engine()->Insert(5, L" World");
77 EXPECT_EQ(L"Hello World", engine()->GetText());
78 EXPECT_EQ(11U, engine()->GetLength());
79
80 engine()->Insert(5, L" New");
81 EXPECT_EQ(L"Hello New World", engine()->GetText());
82
83 engine()->Insert(100, L" Cat");
84 EXPECT_EQ(L"Hello New World Cat", engine()->GetText());
85
86 engine()->Clear();
87
88 engine()->SetHasCharacterLimit(true);
89 engine()->SetCharacterLimit(5);
90 engine()->Insert(0, L"Hello");
91
92 // No delegate
93 engine()->Insert(5, L" World");
94 EXPECT_EQ(L"Hello", engine()->GetText());
95
96 engine()->SetCharacterLimit(8);
97 engine()->Insert(5, L" World");
98 EXPECT_EQ(L"Hello Wo", engine()->GetText());
99
100 engine()->Clear();
101
102 // With Delegate
103 auto delegate = std::make_unique<CFDE_TextEditEngineTest::Delegate>();
104 engine()->SetDelegate(delegate.get());
105
106 engine()->SetCharacterLimit(5);
107 engine()->Insert(0, L"Hello");
108
109 // Insert when full.
110 engine()->Insert(5, L" World");
111 EXPECT_TRUE(delegate->text_is_full);
112 EXPECT_EQ(L"Hello", engine()->GetText());
113 delegate->Reset();
114
115 engine()->SetCharacterLimit(8);
116 engine()->Insert(5, L" World");
117 EXPECT_TRUE(delegate->text_is_full);
118 EXPECT_EQ(L"Hello Wo", engine()->GetText());
119 delegate->Reset();
120 engine()->SetHasCharacterLimit(false);
121
122 engine()->Clear();
123 engine()->Insert(0, L"Hello");
124
125 // Insert Invalid text
126 delegate->fail_validation = true;
127 engine()->EnableValidation(true);
128 engine()->Insert(5, L" World");
129 EXPECT_EQ(L"Hello", engine()->GetText());
130
131 delegate->fail_validation = false;
132 engine()->Insert(5, L" World");
133 EXPECT_EQ(L"Hello World", engine()->GetText());
134 engine()->EnableValidation(false);
135
136 engine()->Clear();
137
138 engine()->Insert(0, L"Hello\nWorld");
139 EXPECT_FALSE(delegate->text_is_full);
140 EXPECT_EQ(L"Hello\nWorld", engine()->GetText());
141 delegate->Reset();
142 engine()->Clear();
143
144 // Insert with limited area and over-fill
145 engine()->LimitHorizontalScroll(true);
146 engine()->SetAvailableWidth(52.0f); // Fits 'Hello Wo'.
147 engine()->Insert(0, L"Hello");
148 EXPECT_FALSE(delegate->text_is_full);
149 engine()->Insert(5, L" World");
150 EXPECT_TRUE(delegate->text_is_full);
151 EXPECT_EQ(L"Hello Wo", engine()->GetText());
152 engine()->LimitHorizontalScroll(false);
153
154 delegate->Reset();
155 engine()->Clear();
156
157 engine()->SetLineSpace(12.0f);
158 engine()->LimitVerticalScroll(true);
159 // Default is one line of text.
160 engine()->Insert(0, L"Hello");
161 EXPECT_FALSE(delegate->text_is_full);
162 engine()->Insert(5, L" Wo\nrld");
163 EXPECT_TRUE(delegate->text_is_full);
164 EXPECT_EQ(L"Hello Wo\n", engine()->GetText());
165 engine()->LimitVerticalScroll(false);
166
167 engine()->SetDelegate(nullptr);
168}
169
171 engine()->SetHasCharacterLimit(true);
172 engine()->Insert(0, L"Hello World");
173 engine()->SetCharacterLimit(5);
174 engine()->Insert(0, L"Not Inserted before ");
175 EXPECT_EQ(L"Hello World", engine()->GetText());
176
177 engine()->SetHasCharacterLimit(false);
178 engine()->Insert(0, L"Inserted before ");
179 engine()->SetHasCharacterLimit(true);
180 engine()->Insert(0, L"Not Inserted before ");
181 EXPECT_EQ(L"Inserted before Hello World", engine()->GetText());
182}
183
185 engine()->SetHasCharacterLimit(true);
186 engine()->SetCharacterLimit(8);
187 engine()->Insert(0, L"Hello");
188 engine()->Insert(5, L" World",
189 CFDE_TextEditEngine::RecordOperation::kSkipNotify);
190 EXPECT_EQ(L"Hello World", engine()->GetText());
191
192 engine()->Insert(0, L"Not inserted");
193 EXPECT_EQ(L"Hello World", engine()->GetText());
194
195 engine()->Delete(5, 1);
196 EXPECT_EQ(L"HelloWorld", engine()->GetText());
197
198 engine()->Insert(0, L"****");
199 EXPECT_EQ(L"*HelloWorld", engine()->GetText());
200}
201
203 engine()->Insert(0, L"||");
204 for (size_t i = 1; i < 1023; ++i) {
205 engine()->Insert(i, L"a");
206 }
207 WideString result = engine()->GetText();
208 ASSERT_EQ(result.GetLength(), 1024u);
209 EXPECT_EQ(result[0], L'|');
210 EXPECT_EQ(result[1], L'a');
211 EXPECT_EQ(result[2], L'a');
212 // ...
213 EXPECT_EQ(result[1022], L'a');
214 EXPECT_EQ(result[1023], L'|');
215}
216
218 EXPECT_EQ(L"", engine()->Delete(0, 50));
219 EXPECT_EQ(L"", engine()->GetText());
220
221 engine()->Insert(0, L"Hello World");
222 EXPECT_EQ(L" World", engine()->Delete(5, 6));
223 EXPECT_EQ(L"Hello", engine()->GetText());
224
225 engine()->Clear();
226 engine()->Insert(0, L"Hello World");
227 EXPECT_EQ(L" ", engine()->Delete(5, 1));
228 EXPECT_EQ(L"HelloWorld", engine()->GetText());
229
230 EXPECT_EQ(L"elloWorld", engine()->Delete(1, 50));
231 EXPECT_EQ(L"H", engine()->GetText());
232}
233
235 EXPECT_EQ(L"", engine()->GetText());
236
237 engine()->Clear();
238 EXPECT_EQ(L"", engine()->GetText());
239
240 engine()->Insert(0, L"Hello World");
241 EXPECT_EQ(L"Hello World", engine()->GetText());
242
243 engine()->Clear();
244 EXPECT_EQ(L"", engine()->GetText());
245 EXPECT_EQ(0U, engine()->GetLength());
246}
247
249 // Out of bounds.
250 EXPECT_EQ(L'\0', engine()->GetChar(0));
251
252 engine()->Insert(0, L"Hello World");
253 EXPECT_EQ(L'H', engine()->GetChar(0));
254 EXPECT_EQ(L'd', engine()->GetChar(engine()->GetLength() - 1));
255 EXPECT_EQ(L' ', engine()->GetChar(5));
256
257 engine()->Insert(5, L" A");
258 EXPECT_EQ(L"Hello A World", engine()->GetText());
259 EXPECT_EQ(L'W', engine()->GetChar(8));
260
261 engine()->EnablePasswordMode(true);
262 EXPECT_EQ(L'*', engine()->GetChar(8));
263
264 engine()->SetAliasChar(L'+');
265 EXPECT_EQ(L'+', engine()->GetChar(8));
266}
267
269 // Out of Bounds.
270 EXPECT_EQ(0, engine()->GetWidthOfChar(0));
271
272 engine()->Insert(0, L"Hello World");
273 EXPECT_EQ(173280, engine()->GetWidthOfChar(0));
274 EXPECT_EQ(133440, engine()->GetWidthOfChar(1));
275
276 engine()->Insert(0, L"\t");
277 EXPECT_EQ(0, engine()->GetWidthOfChar(0));
278}
279
281 EXPECT_EQ(0U, engine()->GetDisplayPos(FDE_TEXTEDITPIECE()).size());
282}
283
285 EXPECT_FALSE(engine()->HasSelection());
286 engine()->SelectAll();
287 EXPECT_FALSE(engine()->HasSelection());
288
289 engine()->Insert(0, L"Hello World");
290 EXPECT_EQ(L"", engine()->DeleteSelectedText());
291
292 EXPECT_FALSE(engine()->HasSelection());
293 engine()->SelectAll();
294 EXPECT_TRUE(engine()->HasSelection());
295 EXPECT_EQ(L"Hello World", engine()->GetSelectedText());
296
297 engine()->ClearSelection();
298 EXPECT_FALSE(engine()->HasSelection());
299 EXPECT_EQ(L"", engine()->GetSelectedText());
300
301 engine()->SelectAll();
302 auto [start_idx, count] = engine()->GetSelection();
303 EXPECT_EQ(0U, start_idx);
304 EXPECT_EQ(11U, count);
305
306 // Selection before gap.
307 EXPECT_EQ(L"Hello World", engine()->GetSelectedText());
308 EXPECT_TRUE(engine()->HasSelection());
309 EXPECT_EQ(L"Hello World", engine()->GetText());
310
311 engine()->Insert(5, L" A");
312 EXPECT_FALSE(engine()->HasSelection());
313 EXPECT_EQ(L"", engine()->GetSelectedText());
314
315 // Selection over the gap.
316 engine()->SelectAll();
317 EXPECT_TRUE(engine()->HasSelection());
318 EXPECT_EQ(L"Hello A World", engine()->GetSelectedText());
319 engine()->Clear();
320
321 engine()->Insert(0, L"Hello World");
322 engine()->SelectAll();
323
324 EXPECT_EQ(L"Hello World", engine()->DeleteSelectedText());
325 EXPECT_FALSE(engine()->HasSelection());
326 EXPECT_EQ(L"", engine()->GetText());
327
328 engine()->Insert(0, L"Hello World");
329 engine()->SetSelection(5, 5);
330 EXPECT_EQ(L" Worl", engine()->DeleteSelectedText());
331 EXPECT_FALSE(engine()->HasSelection());
332 EXPECT_EQ(L"Hellod", engine()->GetText());
333
334 engine()->Clear();
335 engine()->Insert(0, L"Hello World");
336 engine()->SelectAll();
337 engine()->ReplaceSelectedText(L"Goodbye Everybody");
338 EXPECT_FALSE(engine()->HasSelection());
339 EXPECT_EQ(L"Goodbye Everybody", engine()->GetText());
340
341 engine()->Clear();
342 engine()->Insert(0, L"Hello World");
343 engine()->SetSelection(1, 4);
344 engine()->ReplaceSelectedText(L"i,");
345 EXPECT_FALSE(engine()->HasSelection());
346 EXPECT_EQ(L"Hi, World", engine()->GetText());
347
348 // Selection fully after gap.
349 engine()->Clear();
350 engine()->Insert(0, L"Hello");
351 engine()->Insert(0, L"A ");
352 engine()->SetSelection(3, 6);
353 EXPECT_EQ(L"ello", engine()->GetSelectedText());
354
355 engine()->Clear();
356 engine()->Insert(0, L"Hello World");
357 engine()->ClearSelection();
358 engine()->DeleteSelectedText();
359 EXPECT_EQ(L"Hello World", engine()->GetText());
360}
361
363 EXPECT_FALSE(engine()->CanUndo());
364 EXPECT_FALSE(engine()->CanRedo());
365 EXPECT_FALSE(engine()->Undo());
366 EXPECT_FALSE(engine()->Redo());
367
368 engine()->Insert(0, L"Hello");
369 EXPECT_TRUE(engine()->CanUndo());
370 EXPECT_FALSE(engine()->CanRedo());
371 EXPECT_TRUE(engine()->Undo());
372 EXPECT_EQ(L"", engine()->GetText());
373 EXPECT_FALSE(engine()->CanUndo());
374 EXPECT_TRUE(engine()->CanRedo());
375 EXPECT_TRUE(engine()->Redo());
376 EXPECT_EQ(L"Hello", engine()->GetText());
377 EXPECT_TRUE(engine()->CanUndo());
378 EXPECT_FALSE(engine()->CanRedo());
379
380 engine()->Clear();
381 EXPECT_FALSE(engine()->CanUndo());
382 EXPECT_FALSE(engine()->CanRedo());
383
384 engine()->Insert(0, L"Hello World");
385 engine()->SelectAll();
386 engine()->DeleteSelectedText();
387 EXPECT_EQ(L"", engine()->GetText());
388 EXPECT_TRUE(engine()->CanUndo());
389 EXPECT_TRUE(engine()->Undo());
390 EXPECT_EQ(L"Hello World", engine()->GetText());
391 EXPECT_TRUE(engine()->CanRedo());
392 EXPECT_TRUE(engine()->Redo());
393 EXPECT_EQ(L"", engine()->GetText());
394 EXPECT_TRUE(engine()->CanUndo());
395 EXPECT_FALSE(engine()->CanRedo());
396
397 engine()->Insert(0, L"Hello World");
398 engine()->SelectAll();
399 engine()->ReplaceSelectedText(L"Goodbye Friend");
400 EXPECT_EQ(L"Goodbye Friend", engine()->GetText());
401 EXPECT_TRUE(engine()->CanUndo());
402 EXPECT_TRUE(engine()->Undo());
403 EXPECT_EQ(L"Hello World", engine()->GetText());
404 EXPECT_TRUE(engine()->CanRedo());
405 EXPECT_TRUE(engine()->Redo());
406 EXPECT_EQ(L"Goodbye Friend", engine()->GetText());
407
408 engine()->Clear();
409 engine()->SetMaxEditOperationsForTesting(3);
410 engine()->Insert(0, L"First ");
411 engine()->Insert(engine()->GetLength(), L"Second ");
412 engine()->Insert(engine()->GetLength(), L"Third");
413
414 EXPECT_TRUE(engine()->CanUndo());
415 EXPECT_TRUE(engine()->Undo());
416 EXPECT_EQ(L"First Second ", engine()->GetText());
417 EXPECT_TRUE(engine()->CanUndo());
418 EXPECT_TRUE(engine()->Undo());
419 EXPECT_FALSE(
420 engine()->CanUndo()); // Can't undo First; undo buffer too small.
421 EXPECT_EQ(L"First ", engine()->GetText());
422
423 EXPECT_TRUE(engine()->CanRedo());
424 EXPECT_TRUE(engine()->Redo());
425 EXPECT_TRUE(engine()->CanRedo());
426 EXPECT_TRUE(engine()->Redo());
427 EXPECT_FALSE(engine()->CanRedo());
428 EXPECT_EQ(L"First Second Third", engine()->GetText());
429
430 engine()->Clear();
431
432 engine()->SetMaxEditOperationsForTesting(4);
433
434 // Go beyond the max operations limit.
435 engine()->Insert(0, L"H");
436 engine()->Insert(1, L"e");
437 engine()->Insert(2, L"l");
438 engine()->Insert(3, L"l");
439 engine()->Insert(4, L"o");
440 engine()->Insert(5, L" World");
441 EXPECT_EQ(L"Hello World", engine()->GetText());
442
443 // Do A, undo. Do B, undo. Redo should cause B.
444 engine()->Delete(4, 3);
445 EXPECT_EQ(L"Hellorld", engine()->GetText());
446 EXPECT_TRUE(engine()->Undo());
447 EXPECT_EQ(L"Hello World", engine()->GetText());
448 engine()->Delete(5, 6);
449 EXPECT_EQ(L"Hello", engine()->GetText());
450 EXPECT_TRUE(engine()->Undo());
451 EXPECT_EQ(L"Hello World", engine()->GetText());
452 EXPECT_TRUE(engine()->Redo());
453 EXPECT_EQ(L"Hello", engine()->GetText());
454
455 // Undo down to the limit.
456 EXPECT_TRUE(engine()->Undo());
457 EXPECT_EQ(L"Hello World", engine()->GetText());
458 EXPECT_TRUE(engine()->Undo());
459 EXPECT_EQ(L"Hello", engine()->GetText());
460 EXPECT_TRUE(engine()->Undo());
461 EXPECT_EQ(L"Hell", engine()->GetText());
462 EXPECT_FALSE(engine()->Undo());
463 EXPECT_EQ(L"Hell", engine()->GetText());
464}
465
467 engine()->SetFontSize(10.0f);
468 engine()->Insert(0, L"Hello World");
469 EXPECT_EQ(0U, engine()->GetIndexForPoint({0.0f, 0.0f}));
470 EXPECT_EQ(11U, engine()->GetIndexForPoint({999999.0f, 9999999.0f}));
471 EXPECT_EQ(11U, engine()->GetIndexForPoint({999999.0f, 0.0f}));
472 EXPECT_EQ(1U, engine()->GetIndexForPoint({5.0f, 5.0f}));
473 EXPECT_EQ(2U, engine()->GetIndexForPoint({10.0f, 5.0f}));
474}
475
477 engine()->SetFontSize(10.0f);
478 engine()->Insert(0,
479 L"A text long enough to span multiple lines and test "
480 L"getting indexes on multi-line edits.");
481 EXPECT_EQ(0U, engine()->GetIndexForPoint({0.0f, 0.0f}));
482 EXPECT_EQ(87U, engine()->GetIndexForPoint({999999.0f, 9999999.0f}));
483 EXPECT_EQ(18U, engine()->GetIndexForPoint({999999.0f, 0.0f}));
484 EXPECT_EQ(19U, engine()->GetIndexForPoint({1.0f, 10.0f}));
485 EXPECT_EQ(1U, engine()->GetIndexForPoint({5.0f, 5.0f}));
486 EXPECT_EQ(2U, engine()->GetIndexForPoint({10.0f, 5.0f}));
487}
488
490 engine()->SetFontSize(10.0f);
491 engine()->Insert(0, L"Hello World ");
492 EXPECT_EQ(0U, engine()->GetIndexForPoint({0.0f, 0.0f}));
493 EXPECT_EQ(12U, engine()->GetIndexForPoint({999999.0f, 9999999.0f}));
494 EXPECT_EQ(12U, engine()->GetIndexForPoint({999999.0f, 0.0f}));
495}
496
498 engine()->SetFontSize(10.0f);
499 engine()->Insert(0, L"Hello\nWorld");
500 EXPECT_EQ(0U, engine()->GetIndexForPoint({0.0f, 0.0f}));
501 EXPECT_EQ(5U, engine()->GetIndexForPoint({999999.0f, 0.0f}));
502 EXPECT_EQ(6U, engine()->GetIndexForPoint({0.0f, 10.0f}));
503 EXPECT_EQ(11U, engine()->GetIndexForPoint({999999.0f, 9999999.0f}));
504}
505
507 RetainPtr<CFGAS_GEFont> font = engine()->GetFont();
508 ASSERT_TRUE(font);
509
510 // Has font but no text.
511 EXPECT_FALSE(engine()->CanGenerateCharacterInfo());
512
513 // Has font and text.
514 engine()->Insert(0, L"Hi!");
515 EXPECT_TRUE(engine()->CanGenerateCharacterInfo());
516
517 // Has text but no font.
518 engine()->SetFont(nullptr);
519 EXPECT_FALSE(engine()->CanGenerateCharacterInfo());
520
521 // Has no text and no font.
522 engine()->Clear();
523 EXPECT_FALSE(engine()->CanGenerateCharacterInfo());
524}
525
527 std::pair<int32_t, CFX_RectF> char_info;
528
529 engine()->Insert(0, L"Hi!");
530 ASSERT_EQ(3U, engine()->GetLength());
531
532 char_info = engine()->GetCharacterInfo(0);
533 EXPECT_EQ(0, char_info.first);
534 EXPECT_FLOAT_EQ(0.0f, char_info.second.Left());
535 EXPECT_FLOAT_EQ(0.0f, char_info.second.Top());
536 EXPECT_FLOAT_EQ(8.664f, char_info.second.Width());
537 EXPECT_FLOAT_EQ(12.0f, char_info.second.Height());
538
539 char_info = engine()->GetCharacterInfo(1);
540 EXPECT_EQ(0, char_info.first);
541 EXPECT_FLOAT_EQ(8.664f, char_info.second.Left());
542 EXPECT_FLOAT_EQ(0.0f, char_info.second.Top());
543 EXPECT_FLOAT_EQ(3.324f, char_info.second.Width());
544 EXPECT_FLOAT_EQ(12.0f, char_info.second.Height());
545
546 char_info = engine()->GetCharacterInfo(2);
547 EXPECT_EQ(0, char_info.first);
548 EXPECT_FLOAT_EQ(11.988f, char_info.second.Left());
549 EXPECT_FLOAT_EQ(0.0f, char_info.second.Top());
550 EXPECT_FLOAT_EQ(3.996f, char_info.second.Width());
551 EXPECT_FLOAT_EQ(12.0f, char_info.second.Height());
552
553 // Allow retrieving the character info for the end of the text, as that
554 // information can be used to determine where to draw a cursor positioned at
555 // the end.
556 char_info = engine()->GetCharacterInfo(3);
557 EXPECT_EQ(0, char_info.first);
558 EXPECT_FLOAT_EQ(15.984, char_info.second.Left());
559 EXPECT_FLOAT_EQ(0.0f, char_info.second.Top());
560 EXPECT_FLOAT_EQ(0.0f, char_info.second.Width());
561 EXPECT_FLOAT_EQ(12.0f, char_info.second.Height());
562}
563
565 auto [start_idx, count] = engine()->BoundsForWordAt(100);
566 EXPECT_EQ(0U, start_idx);
567 EXPECT_EQ(0U, count);
568 engine()->SetSelection(start_idx, count);
569 EXPECT_EQ(L"", engine()->GetSelectedText());
570
571 engine()->Clear();
572 engine()->Insert(0, L"Hello");
573 std::tie(start_idx, count) = engine()->BoundsForWordAt(0);
574 EXPECT_EQ(0U, start_idx);
575 EXPECT_EQ(5U, count);
576 engine()->SetSelection(start_idx, count);
577 EXPECT_EQ(L"Hello", engine()->GetSelectedText());
578
579 engine()->Clear();
580 engine()->Insert(0, L"Hello World");
581 std::tie(start_idx, count) = engine()->BoundsForWordAt(100);
582 EXPECT_EQ(0U, start_idx);
583 EXPECT_EQ(0U, count);
584 engine()->SetSelection(start_idx, count);
585 EXPECT_EQ(L"", engine()->GetSelectedText());
586
587 std::tie(start_idx, count) = engine()->BoundsForWordAt(0);
588 EXPECT_EQ(0U, start_idx);
589 EXPECT_EQ(5U, count);
590 engine()->SetSelection(start_idx, count);
591 EXPECT_EQ(L"Hello", engine()->GetSelectedText());
592
593 std::tie(start_idx, count) = engine()->BoundsForWordAt(1);
594 EXPECT_EQ(0U, start_idx);
595 EXPECT_EQ(5U, count);
596 engine()->SetSelection(start_idx, count);
597 EXPECT_EQ(L"Hello", engine()->GetSelectedText());
598
599 std::tie(start_idx, count) = engine()->BoundsForWordAt(4);
600 EXPECT_EQ(0U, start_idx);
601 EXPECT_EQ(5U, count);
602 engine()->SetSelection(start_idx, count);
603 EXPECT_EQ(L"Hello", engine()->GetSelectedText());
604
605 // Select the space
606 std::tie(start_idx, count) = engine()->BoundsForWordAt(5);
607 EXPECT_EQ(5U, start_idx);
608 EXPECT_EQ(1U, count);
609 engine()->SetSelection(start_idx, count);
610 EXPECT_EQ(L" ", engine()->GetSelectedText());
611
612 std::tie(start_idx, count) = engine()->BoundsForWordAt(6);
613 EXPECT_EQ(6U, start_idx);
614 EXPECT_EQ(5U, count);
615 engine()->SetSelection(start_idx, count);
616 EXPECT_EQ(L"World", engine()->GetSelectedText());
617
618 engine()->Clear();
619 engine()->Insert(0, L"123 456 789");
620 std::tie(start_idx, count) = engine()->BoundsForWordAt(5);
621 engine()->SetSelection(start_idx, count);
622 EXPECT_EQ(L"456", engine()->GetSelectedText());
623
624 engine()->Clear();
625 engine()->Insert(0, L"123def789");
626 std::tie(start_idx, count) = engine()->BoundsForWordAt(5);
627 engine()->SetSelection(start_idx, count);
628 EXPECT_EQ(L"123def789", engine()->GetSelectedText());
629
630 engine()->Clear();
631 engine()->Insert(0, L"abc456ghi");
632 std::tie(start_idx, count) = engine()->BoundsForWordAt(5);
633 engine()->SetSelection(start_idx, count);
634 EXPECT_EQ(L"abc456ghi", engine()->GetSelectedText());
635
636 engine()->Clear();
637 engine()->Insert(0, L"hello, world");
638 std::tie(start_idx, count) = engine()->BoundsForWordAt(0);
639 engine()->SetSelection(start_idx, count);
640 EXPECT_EQ(L"hello", engine()->GetSelectedText());
641
642 engine()->Clear();
643 engine()->Insert(0, L"hello, world");
644 std::tie(start_idx, count) = engine()->BoundsForWordAt(5);
645 engine()->SetSelection(start_idx, count);
646 EXPECT_EQ(L",", engine()->GetSelectedText());
647
648 engine()->Clear();
649 engine()->Insert(0, L"np-complete");
650 std::tie(start_idx, count) = engine()->BoundsForWordAt(6);
651 engine()->SetSelection(start_idx, count);
652 EXPECT_EQ(L"complete", engine()->GetSelectedText());
653
654 engine()->Clear();
655 engine()->Insert(0, L"(123) 456-7890");
656 std::tie(start_idx, count) = engine()->BoundsForWordAt(0);
657 engine()->SetSelection(start_idx, count);
658 EXPECT_EQ(L"(", engine()->GetSelectedText());
659
660 std::tie(start_idx, count) = engine()->BoundsForWordAt(1);
661 engine()->SetSelection(start_idx, count);
662 EXPECT_EQ(L"123", engine()->GetSelectedText());
663
664 std::tie(start_idx, count) = engine()->BoundsForWordAt(7);
665 engine()->SetSelection(start_idx, count);
666 EXPECT_EQ(L"456", engine()->GetSelectedText());
667
668 std::tie(start_idx, count) = engine()->BoundsForWordAt(11);
669 engine()->SetSelection(start_idx, count);
670 EXPECT_EQ(L"7890", engine()->GetSelectedText());
671
672 // Tests from:
673 // http://unicode.org/Public/UNIDATA/auxiliary/WordBreakTest.html#samples
674 struct bounds {
675 size_t start;
676 size_t end;
677 };
678 struct {
679 const wchar_t* str;
680 std::vector<const wchar_t*> results;
681 } tests[] = {
682 // {L"\r\na\n\u0308", {L"\r\n", L"a", L"\n", L"\u0308"}},
683 // {L"a\u0308", {L"a\u0308"}},
684 // {L" \u200d\u0646", {L" \u200d", L"\u0646"}},
685 // {L"\u0646\u200d ", {L"\u0646\u200d", L" "}},
686 {L"AAA", {L"AAA"}},
687 {L"A:A", {L"A:A"}},
688 {L"A::A", {L"A", L":", L":", L"A"}},
689 // {L"\u05d0'", {L"\u05d0'"}},
690 // {L"\u05d0\"\u05d0", {L"\u05d0\"\u05d0"}},
691 {L"A00A", {L"A00A"}},
692 {L"0,0", {L"0,0"}},
693 {L"0,,0", {L"0", L",", L",", L"0"}},
694 {L"\u3031\u3031", {L"\u3031\u3031"}},
695 {L"A_0_\u3031_", {L"A_0_\u3031_"}},
696 {L"A__A", {L"A__A"}},
697 // {L"\u200d\u2640", {L"\u200d\u2640"}},
698 // {L"a\u0308\u200b\u0308b", {L"a\u0308\u200b\u0308b"}},
699 };
700
701 for (auto t : tests) {
702 engine()->Clear();
703 engine()->Insert(0, t.str);
704
705 size_t idx = 0;
706 for (const auto* res : t.results) {
707 std::tie(start_idx, count) = engine()->BoundsForWordAt(idx);
708 engine()->SetSelection(start_idx, count);
709 EXPECT_EQ(res, engine()->GetSelectedText()) << "Input: '" << t.str << "'";
710 idx += count;
711 }
712 }
713}
714
716 engine()->Clear();
717 engine()->Insert(0, L"Hello");
718
719 EXPECT_EQ(0U, engine()->GetIndexLeft(0));
720 EXPECT_EQ(5U, engine()->GetIndexRight(5));
721 EXPECT_EQ(2U, engine()->GetIndexUp(2));
722 EXPECT_EQ(2U, engine()->GetIndexDown(2));
723 EXPECT_EQ(1U, engine()->GetIndexLeft(2));
724 EXPECT_EQ(3U, engine()->GetIndexRight(2));
725 EXPECT_EQ(0U, engine()->GetIndexAtStartOfLine(2));
726 EXPECT_EQ(5U, engine()->GetIndexAtEndOfLine(2));
727
728 engine()->Clear();
729 engine()->Insert(0, L"The book is \"مدخل إلى C++\"");
730 EXPECT_FALSE(FX_IsOdd(engine()->GetCharacterInfo(3).first));
731 EXPECT_EQ(2U, engine()->GetIndexLeft(3));
732 EXPECT_EQ(4U, engine()->GetIndexRight(3));
733 EXPECT_TRUE(FX_IsOdd(engine()->GetCharacterInfo(15).first));
734 EXPECT_EQ(14U, engine()->GetIndexLeft(15));
735 EXPECT_EQ(16U, engine()->GetIndexRight(15));
736 EXPECT_FALSE(FX_IsOdd(engine()->GetCharacterInfo(23).first));
737 EXPECT_EQ(22U, engine()->GetIndexLeft(23));
738 EXPECT_EQ(24U, engine()->GetIndexRight(23));
739
740 engine()->Clear();
741 engine()->Insert(0, L"Hello\r\nWorld\r\nTest");
742 // Move to end of Hello from start of World.
743 engine()->SetSelection(engine()->GetIndexLeft(7U), 7);
744 EXPECT_EQ(L"\r\nWorld", engine()->GetSelectedText());
745
746 // Second letter in Hello from second letter in World.
747 engine()->SetSelection(engine()->GetIndexUp(8U), 2);
748 EXPECT_EQ(L"el", engine()->GetSelectedText());
749
750 // Second letter in World from second letter in Test.
751 engine()->SetSelection(engine()->GetIndexUp(15U), 2);
752 EXPECT_EQ(L"or", engine()->GetSelectedText());
753
754 // Second letter in World from second letter in Hello.
755 engine()->SetSelection(engine()->GetIndexDown(1U), 2);
756 EXPECT_EQ(L"or", engine()->GetSelectedText());
757
758 // Second letter in Test from second letter in World.
759 engine()->SetSelection(engine()->GetIndexDown(8U), 2);
760 EXPECT_EQ(L"es", engine()->GetSelectedText());
761
762 size_t start_idx = engine()->GetIndexAtStartOfLine(8U);
763 size_t end_idx = engine()->GetIndexAtEndOfLine(8U);
764 engine()->SetSelection(start_idx, end_idx - start_idx);
765 EXPECT_EQ(L"World", engine()->GetSelectedText());
766
767 // Move past \r\n to before W.
768 engine()->SetSelection(engine()->GetIndexRight(5U), 5);
769 EXPECT_EQ(L"World", engine()->GetSelectedText());
770
771 engine()->Clear();
772 engine()->Insert(0, L"Short\nAnd a very long line");
773 engine()->SetSelection(engine()->GetIndexUp(14U), 11);
774 EXPECT_EQ(L"\nAnd a very", engine()->GetSelectedText());
775
776 engine()->Clear();
777 engine()->Insert(0, L"A Very long line\nShort");
778 EXPECT_EQ(engine()->GetLength(), engine()->GetIndexDown(8U));
779
780 engine()->Clear();
781 engine()->Insert(0, L"Hello\rWorld\rTest");
782 // Move to end of Hello from start of World.
783 engine()->SetSelection(engine()->GetIndexLeft(6U), 6);
784 EXPECT_EQ(L"\rWorld", engine()->GetSelectedText());
785
786 // Second letter in Hello from second letter in World.
787 engine()->SetSelection(engine()->GetIndexUp(7U), 2);
788 EXPECT_EQ(L"el", engine()->GetSelectedText());
789
790 // Second letter in World from second letter in Test.
791 engine()->SetSelection(engine()->GetIndexUp(13U), 2);
792 EXPECT_EQ(L"or", engine()->GetSelectedText());
793
794 // Second letter in World from second letter in Hello.
795 engine()->SetSelection(engine()->GetIndexDown(1U), 2);
796 EXPECT_EQ(L"or", engine()->GetSelectedText());
797
798 // Second letter in Test from second letter in World.
799 engine()->SetSelection(engine()->GetIndexDown(7U), 2);
800 EXPECT_EQ(L"es", engine()->GetSelectedText());
801
802 start_idx = engine()->GetIndexAtStartOfLine(7U);
803 end_idx = engine()->GetIndexAtEndOfLine(7U);
804 engine()->SetSelection(start_idx, end_idx - start_idx);
805 EXPECT_EQ(L"World", engine()->GetSelectedText());
806
807 // Move past \r to before W.
808 engine()->SetSelection(engine()->GetIndexRight(5U), 5);
809 EXPECT_EQ(L"World", engine()->GetSelectedText());
810
811 engine()->Clear();
812 engine()->Insert(0, L"Hello\nWorld\nTest");
813 // Move to end of Hello from start of World.
814 engine()->SetSelection(engine()->GetIndexLeft(6U), 6);
815 EXPECT_EQ(L"\nWorld", engine()->GetSelectedText());
816
817 // Second letter in Hello from second letter in World.
818 engine()->SetSelection(engine()->GetIndexUp(7U), 2);
819 EXPECT_EQ(L"el", engine()->GetSelectedText());
820
821 // Second letter in World from second letter in Test.
822 engine()->SetSelection(engine()->GetIndexUp(13U), 2);
823 EXPECT_EQ(L"or", engine()->GetSelectedText());
824
825 // Second letter in World from second letter in Hello.
826 engine()->SetSelection(engine()->GetIndexDown(1U), 2);
827 EXPECT_EQ(L"or", engine()->GetSelectedText());
828
829 // Second letter in Test from second letter in World.
830 engine()->SetSelection(engine()->GetIndexDown(7U), 2);
831 EXPECT_EQ(L"es", engine()->GetSelectedText());
832
833 start_idx = engine()->GetIndexAtStartOfLine(7U);
834 end_idx = engine()->GetIndexAtEndOfLine(7U);
835 engine()->SetSelection(start_idx, end_idx - start_idx);
836 EXPECT_EQ(L"World", engine()->GetSelectedText());
837
838 // Move past \r to before W.
839 engine()->SetSelection(engine()->GetIndexRight(5U), 5);
840 EXPECT_EQ(L"World", engine()->GetSelectedText());
841}
842
843} // namespace pdfium
bool OnValidate(const WideString &wsText) override
void OnTextWillChange(CFDE_TextEditEngine::TextChange *change) override
~CFDE_TextEditEngineTest() override=default
#define FX_IsOdd(a)
TEST_F(CFDE_TextEditEngineTest, Insert)
fxcrt::WideString WideString
Definition widestring.h:207