1e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov// Copyright 2015 PDFium Authors. All rights reserved. 2e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov// Use of this source code is governed by a BSD-style license that can be 3e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov// found in the LICENSE file. 4e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 5e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include "../../public/fpdf_text.h" 6e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include "../../public/fpdfview.h" 7e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include "../../testing/embedder_test.h" 8e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include "testing/gtest/include/gtest/gtest.h" 9e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 10e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganovnamespace { 11e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 12e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganovstatic bool check_unsigned_shorts(const char* expected, 13e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov const unsigned short* actual, 14e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov size_t length) { 15e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov if (length > strlen(expected) + 1) { 16e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov return false; 17e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov } 18e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov for (size_t i = 0; i < length; ++i) { 19e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov if (actual[i] != static_cast<unsigned short>(expected[i])) { 20e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov return false; 21e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov } 22e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov } 23e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov return true; 24e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov} 25e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 26e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov} // namespace 27e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 28e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganovclass FPDFTextEmbeddertest : public EmbedderTest { 29e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}; 30e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 31e6986e1e8d4a57987f47c215490cb080a65ee29aSvet GanovTEST_F(FPDFTextEmbeddertest, Text) { 32e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_TRUE(OpenDocument("testing/resources/hello_world.pdf")); 33e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDF_PAGE page = LoadPage(0); 34e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_NE(nullptr, page); 35e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 36e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page); 37e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_NE(nullptr, textpage); 38e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 39e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov static const char expected[] = "Hello, world!\r\nGoodbye, world!"; 40e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov unsigned short fixed_buffer[128]; 41e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov memset(fixed_buffer, 0xbd, sizeof(fixed_buffer)); 42e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 43e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Check includes the terminating NUL that is provided. 44e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(sizeof(expected), FPDFText_GetText(textpage, 0, 128, fixed_buffer)); 45e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_TRUE(check_unsigned_shorts(expected, fixed_buffer, sizeof(expected))); 46e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 47e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Count does not include the terminating NUL in the string literal. 48e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(sizeof(expected) - 1, FPDFText_CountChars(textpage)); 49e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov for (size_t i = 0; i < sizeof(expected) - 1; ++i) { 50e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(expected[i], FPDFText_GetUnicode(textpage, i)) << " at " << i; 51e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov } 52e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 53e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(12.0, FPDFText_GetFontSize(textpage, 0)); 54e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(16.0, FPDFText_GetFontSize(textpage, 15)); 55e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 56e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov double left = 0.0; 57e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov double right = 0.0; 58e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov double bottom = 0.0; 59e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov double top = 0.0; 60e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDFText_GetCharBox(textpage, 4, &left, &right, &bottom, &top); 61e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_NEAR(41.071, left, 0.001); 62e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_NEAR(46.243, right, 0.001); 63e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_NEAR(49.844, bottom, 0.001); 64e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_NEAR(55.520, top, 0.001); 65e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 66e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(4, FPDFText_GetCharIndexAtPos( 67e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov textpage, 42.0, 50.0, 1.0, 1.0)); 68e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(-1, FPDFText_GetCharIndexAtPos( 69e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov textpage, 0.0, 0.0, 1.0, 1.0)); 70e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(-1, FPDFText_GetCharIndexAtPos( 71e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov textpage, 199.0, 199.0, 1.0, 1.0)); 72e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 73e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Test out of range indicies. 74e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(-1, FPDFText_GetCharIndexAtPos( 75e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov textpage, 42.0, 10000000.0, 1.0, 1.0)); 76e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(-1, FPDFText_GetCharIndexAtPos( 77e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov textpage, -1.0, 50.0, 1.0, 1.0)); 78e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 79e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Count does not include the terminating NUL in the string literal. 80e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(2, FPDFText_CountRects(textpage, 0, sizeof(expected) - 1)); 81e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 82e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov left = 0.0; 83e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov right = 0.0; 84e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov bottom = 0.0; 85e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov top = 0.0; 86e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDFText_GetRect(textpage, 1, &left, &top, &right, &bottom); 87e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_NEAR(20.847, left, 0.001); 88e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_NEAR(135.167, right, 0.001); 89e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_NEAR(96.655, bottom, 0.001); 90e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_NEAR(116.000, top, 0.001); 91e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 92e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Test out of range indicies set outputs to (0.0, 0.0, 0.0, 0.0). 93e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov left = -1.0; 94e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov right = -1.0; 95e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov bottom = -1.0; 96e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov top = -1.0; 97e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDFText_GetRect(textpage, -1, &left, &top, &right, &bottom); 98e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0.0, left); 99e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0.0, right); 100e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0.0, bottom); 101e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0.0, top); 102e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 103e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov left = -2.0; 104e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov right = -2.0; 105e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov bottom = -2.0; 106e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov top = -2.0; 107e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDFText_GetRect(textpage, 2, &left, &top, &right, &bottom); 108e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0.0, left); 109e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0.0, right); 110e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0.0, bottom); 111e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0.0, top); 112e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 113e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(9, FPDFText_GetBoundedText( 114e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov textpage, 41.0, 56.0, 82.0, 48.0, 0, 0)); 115e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 116e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Extract starting at character 4 as above. 117e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov memset(fixed_buffer, 0xbd, sizeof(fixed_buffer)); 118e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(1, FPDFText_GetBoundedText( 119e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov textpage, 41.0, 56.0, 82.0, 48.0, fixed_buffer, 1)); 120e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_TRUE(check_unsigned_shorts(expected + 4, fixed_buffer, 1)); 121e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0xbdbd, fixed_buffer[1]); 122e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 123e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov memset(fixed_buffer, 0xbd, sizeof(fixed_buffer)); 124e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(9, FPDFText_GetBoundedText( 125e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov textpage, 41.0, 56.0, 82.0, 48.0, fixed_buffer, 9)); 126e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_TRUE(check_unsigned_shorts(expected + 4, fixed_buffer, 9)); 127e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0xbdbd, fixed_buffer[9]); 128e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 129e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov memset(fixed_buffer, 0xbd, sizeof(fixed_buffer)); 130e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(10, FPDFText_GetBoundedText( 131e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov textpage, 41.0, 56.0, 82.0, 48.0, fixed_buffer, 128)); 132e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_TRUE(check_unsigned_shorts(expected + 4, fixed_buffer, 9)); 133e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0u, fixed_buffer[9]); 134e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0xbdbd, fixed_buffer[10]); 135e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 136e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDFText_ClosePage(textpage); 137e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov UnloadPage(page); 138e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov} 139e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 140e6986e1e8d4a57987f47c215490cb080a65ee29aSvet GanovTEST_F(FPDFTextEmbeddertest, TextSearch) { 141e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_TRUE(OpenDocument("testing/resources/hello_world.pdf")); 142e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDF_PAGE page = LoadPage(0); 143e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_NE(nullptr, page); 144e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 145e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page); 146e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_NE(nullptr, textpage); 147e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 148e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Avoid issues with system wchar_t width vs. FPDF_WideString. 149e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov const unsigned short nope[] = { 'n', 'o', 'p', 'e', '\0' }; 150e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov const unsigned short world[] = { 'w', 'o', 'r', 'l', 'd', '\0' }; 151e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov const unsigned short world_caps[] = { 'W', 'O', 'R', 'L', 'D', '\0' }; 152e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov const unsigned short world_substr[] = { 'o', 'r', 'l', 'd', '\0' }; 153e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 154e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // No occurences of "nope" in test page. 155e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDF_SCHHANDLE search = FPDFText_FindStart(textpage, nope, 0, 0); 156e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_NE(nullptr, search); 157e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0, FPDFText_GetSchResultIndex(search)); 158e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0, FPDFText_GetSchCount(search)); 159e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 160e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Advancing finds nothing. 161e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_FALSE(FPDFText_FindNext(search)); 162e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0, FPDFText_GetSchResultIndex(search)); 163e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0, FPDFText_GetSchCount(search)); 164e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 165e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Retreating finds nothing. 166e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_FALSE(FPDFText_FindPrev(search)); 167e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0, FPDFText_GetSchResultIndex(search)); 168e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0, FPDFText_GetSchCount(search)); 169e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDFText_FindClose(search); 170e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 171e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Two occurences of "world" in test page. 172e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov search = FPDFText_FindStart(textpage, world, 0, 2); 173e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_NE(nullptr, search); 174e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 175e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Remains not found until advanced. 176e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0, FPDFText_GetSchResultIndex(search)); 177e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0, FPDFText_GetSchCount(search)); 178e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 179e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // First occurence of "world" in this test page. 180e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_TRUE(FPDFText_FindNext(search)); 181e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(7, FPDFText_GetSchResultIndex(search)); 182e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(5, FPDFText_GetSchCount(search)); 183e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 184e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Last occurence of "world" in this test page. 185e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_TRUE(FPDFText_FindNext(search)); 186e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(24, FPDFText_GetSchResultIndex(search)); 187e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(5, FPDFText_GetSchCount(search)); 188e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 189e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Found position unchanged when fails to advance. 190e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_FALSE(FPDFText_FindNext(search)); 191e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(24, FPDFText_GetSchResultIndex(search)); 192e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(5, FPDFText_GetSchCount(search)); 193e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 194e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Back to first occurence. 195e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_TRUE(FPDFText_FindPrev(search)); 196e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(7, FPDFText_GetSchResultIndex(search)); 197e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(5, FPDFText_GetSchCount(search)); 198e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 199e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Found position unchanged when fails to retreat. 200e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_FALSE(FPDFText_FindPrev(search)); 201e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(7, FPDFText_GetSchResultIndex(search)); 202e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(5, FPDFText_GetSchCount(search)); 203e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDFText_FindClose(search); 204e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 205e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Exact search unaffected by case sensitiity and whole word flags. 206e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov search = FPDFText_FindStart( 207e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov textpage, world, FPDF_MATCHCASE | FPDF_MATCHWHOLEWORD, 0); 208e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_NE(nullptr, search); 209e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_TRUE(FPDFText_FindNext(search)); 210e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(7, FPDFText_GetSchResultIndex(search)); 211e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(5, FPDFText_GetSchCount(search)); 212e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDFText_FindClose(search); 213e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 214e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Default is case-insensitive, so matching agaist caps works. 215e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov search = FPDFText_FindStart(textpage, world_caps, 0, 0); 216e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_NE(nullptr, search); 217e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_TRUE(FPDFText_FindNext(search)); 218e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(7, FPDFText_GetSchResultIndex(search)); 219e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(5, FPDFText_GetSchCount(search)); 220e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDFText_FindClose(search); 221e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 222e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // But can be made case sensitive, in which case this fails. 223e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov search = FPDFText_FindStart(textpage, world_caps, FPDF_MATCHCASE, 0); 224e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_FALSE(FPDFText_FindNext(search)); 225e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0, FPDFText_GetSchResultIndex(search)); 226e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0, FPDFText_GetSchCount(search)); 227e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDFText_FindClose(search); 228e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 229e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Default is match anywhere within word, so matching substirng works. 230e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov search = FPDFText_FindStart(textpage, world_substr, 0, 0); 231e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_TRUE(FPDFText_FindNext(search)); 232e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(8, FPDFText_GetSchResultIndex(search)); 233e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(4, FPDFText_GetSchCount(search)); 234e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDFText_FindClose(search); 235e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 236e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // But can be made to mach word boundaries, in which case this fails. 237e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov search = FPDFText_FindStart(textpage, world_substr, FPDF_MATCHWHOLEWORD, 0); 238e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_FALSE(FPDFText_FindNext(search)); 239e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // TODO(tsepez): investigate strange index/count values in this state. 240e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDFText_FindClose(search); 241e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 242e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDFText_ClosePage(textpage); 243e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov UnloadPage(page); 244e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov} 245e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 246e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov// Test that the page has characters despite a bad stream length. 247e6986e1e8d4a57987f47c215490cb080a65ee29aSvet GanovTEST_F(FPDFTextEmbeddertest, StreamLengthPastEndOfFile) { 248e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_TRUE(OpenDocument("testing/resources/bug_57.pdf")); 249e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDF_PAGE page = LoadPage(0); 250e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_NE(nullptr, page); 251e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 252e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page); 253e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_NE(nullptr, textpage); 254e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(13, FPDFText_CountChars(textpage)); 255e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 256e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDFText_ClosePage(textpage); 257e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov UnloadPage(page); 258e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov} 259e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 260e6986e1e8d4a57987f47c215490cb080a65ee29aSvet GanovTEST_F(FPDFTextEmbeddertest, WebLinks) { 261e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_TRUE(OpenDocument("testing/resources/weblinks.pdf")); 262e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDF_PAGE page = LoadPage(0); 263e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_NE(nullptr, page); 264e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 265e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page); 266e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_NE(nullptr, textpage); 267e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 268e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDF_PAGELINK pagelink = FPDFLink_LoadWebLinks(textpage); 269e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_NE(nullptr, pagelink); 270e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 271e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Page contains two HTTP-style URLs. 272e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(2, FPDFLink_CountWebLinks(pagelink)); 273e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 274e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Only a terminating NUL required for bogus links. 275e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(1, FPDFLink_GetURL(pagelink, 2, nullptr, 0)); 276e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(1, FPDFLink_GetURL(pagelink, 1400, nullptr, 0)); 277e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(1, FPDFLink_GetURL(pagelink, -1, nullptr, 0)); 278e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 279e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Query the number of characters required for each link (incl NUL). 280e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(25, FPDFLink_GetURL(pagelink, 0, nullptr, 0)); 281e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(26, FPDFLink_GetURL(pagelink, 1, nullptr, 0)); 282e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 283e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov static const char expected_url[] = "http://example.com?q=foo"; 284e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov unsigned short fixed_buffer[128]; 285e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 286e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Retrieve a link with too small a buffer. Buffer will not be 287e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // NUL-terminated, but must not be modified past indicated length, 288e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // so pre-fill with a pattern to check write bounds. 289e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov memset(fixed_buffer, 0xbd, sizeof(fixed_buffer)); 290e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(1, FPDFLink_GetURL(pagelink, 0, fixed_buffer, 1)); 291e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_TRUE(check_unsigned_shorts(expected_url, fixed_buffer, 1)); 292e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0xbdbd, fixed_buffer[1]); 293e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 294e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Check buffer that doesn't have space for a terminating NUL. 295e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov memset(fixed_buffer, 0xbd, sizeof(fixed_buffer)); 296e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(sizeof(expected_url) - 1, FPDFLink_GetURL( 297e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov pagelink, 0, fixed_buffer, sizeof(expected_url) - 1)); 298e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_TRUE(check_unsigned_shorts( 299e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov expected_url, fixed_buffer, sizeof(expected_url) - 1)); 300e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0xbdbd, fixed_buffer[sizeof(expected_url) - 1]); 301e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 302e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Retreive link with exactly-sized buffer. 303e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov memset(fixed_buffer, 0xbd, sizeof(fixed_buffer)); 304e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(sizeof(expected_url), FPDFLink_GetURL( 305e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov pagelink, 0, fixed_buffer, sizeof(expected_url))); 306e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_TRUE(check_unsigned_shorts( 307e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov expected_url, fixed_buffer, sizeof(expected_url))); 308e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0u, fixed_buffer[sizeof(expected_url) - 1]); 309e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0xbdbd, fixed_buffer[sizeof(expected_url)]); 310e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 311e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Retreive link with ample-sized-buffer. 312e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov memset(fixed_buffer, 0xbd, sizeof(fixed_buffer)); 313e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(sizeof(expected_url), FPDFLink_GetURL( 314e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov pagelink, 0, fixed_buffer, 128)); 315e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_TRUE(check_unsigned_shorts( 316e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov expected_url, fixed_buffer, sizeof(expected_url))); 317e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0u, fixed_buffer[sizeof(expected_url) - 1]); 318e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0xbdbd, fixed_buffer[sizeof(expected_url)]); 319e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 320e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Each link rendered in a single rect in this test page. 321e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(1, FPDFLink_CountRects(pagelink, 0)); 322e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(1, FPDFLink_CountRects(pagelink, 1)); 323e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 324e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Each link rendered in a single rect in this test page. 325e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0, FPDFLink_CountRects(pagelink, -1)); 326e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0, FPDFLink_CountRects(pagelink, 2)); 327e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(0, FPDFLink_CountRects(pagelink, 10000)); 328e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 329e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Check boundary of valid link index with valid rect index. 330e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov double left = 0.0; 331e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov double right = 0.0; 332e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov double top = 0.0; 333e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov double bottom = 0.0; 334e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDFLink_GetRect(pagelink, 0, 0, &left, &top, &right, &bottom); 335e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_NEAR(50.791, left, 0.001); 336e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_NEAR(187.963, right, 0.001); 337e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_NEAR(97.624, bottom, 0.001); 338e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_NEAR(108.736, top, 0.001); 339e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 340e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Check that valid link with invalid rect index leaves parameters unchanged. 341e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov left = -1.0; 342e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov right = -1.0; 343e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov top = -1.0; 344e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov bottom = -1.0; 345e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDFLink_GetRect(pagelink, 0, 1, &left, &top, &right, &bottom); 346e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(-1.0, left); 347e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(-1.0, right); 348e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(-1.0, bottom); 349e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(-1.0, top); 350e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 351e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov // Check that invalid link index leaves parameters unchanged. 352e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov left = -2.0; 353e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov right = -2.0; 354e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov top = -2.0; 355e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov bottom = -2.0; 356e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDFLink_GetRect(pagelink, -1, 0, &left, &top, &right, &bottom); 357e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(-2.0, left); 358e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(-2.0, right); 359e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(-2.0, bottom); 360e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov EXPECT_EQ(-2.0, top); 361e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov 362e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDFLink_CloseWebLinks(pagelink); 363e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov FPDFText_ClosePage(textpage); 364e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov UnloadPage(page); 365e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov} 366