PageRenderTime 34ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/qtwebengine/src/3rdparty/chromium/third_party/WebKit/Source/core/page/PrintContextTest.cpp

https://bitbucket.org/lotiuss/qt-5.11.0
C++ | 369 lines | 322 code | 44 blank | 3 comment | 5 complexity | b68d24a85a017cf91a24903a979db3bb MD5 | raw file
Possible License(s): GPL-3.0, MPL-2.0, CC-BY-SA-3.0, LGPL-2.0, Unlicense, BSD-3-Clause, Apache-2.0, LGPL-3.0, MIT, WTFPL, GPL-2.0, MPL-2.0-no-copyleft-exception, AGPL-3.0, LGPL-2.1, BSD-2-Clause, 0BSD, JSON, ISC
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "core/page/PrintContext.h"
  5. #include <memory>
  6. #include "core/dom/Document.h"
  7. #include "core/frame/LocalFrameView.h"
  8. #include "core/html/HTMLElement.h"
  9. #include "core/layout/LayoutTestHelper.h"
  10. #include "core/layout/LayoutView.h"
  11. #include "core/paint/PaintLayer.h"
  12. #include "core/paint/PaintLayerPainter.h"
  13. #include "core/testing/DummyPageHolder.h"
  14. #include "platform/graphics/GraphicsContext.h"
  15. #include "platform/graphics/paint/DrawingRecorder.h"
  16. #include "platform/graphics/paint/PaintRecordBuilder.h"
  17. #include "platform/scroll/ScrollbarTheme.h"
  18. #include "platform/text/TextStream.h"
  19. #include "testing/gtest/include/gtest/gtest.h"
  20. #include "third_party/skia/include/core/SkCanvas.h"
  21. namespace blink {
  22. const int kPageWidth = 800;
  23. const int kPageHeight = 600;
  24. class MockPageContextCanvas : public SkCanvas {
  25. public:
  26. enum OperationType { kDrawRect, kDrawPoint };
  27. struct Operation {
  28. OperationType type;
  29. SkRect rect;
  30. };
  31. MockPageContextCanvas() : SkCanvas(kPageWidth, kPageHeight) {}
  32. ~MockPageContextCanvas() override = default;
  33. void onDrawAnnotation(const SkRect& rect,
  34. const char key[],
  35. SkData* value) override {
  36. if (rect.width() == 0 && rect.height() == 0) {
  37. SkPoint point = getTotalMatrix().mapXY(rect.x(), rect.y());
  38. Operation operation = {kDrawPoint,
  39. SkRect::MakeXYWH(point.x(), point.y(), 0, 0)};
  40. recorded_operations_.push_back(operation);
  41. } else {
  42. Operation operation = {kDrawRect, rect};
  43. getTotalMatrix().mapRect(&operation.rect);
  44. recorded_operations_.push_back(operation);
  45. }
  46. }
  47. const Vector<Operation>& RecordedOperations() const {
  48. return recorded_operations_;
  49. }
  50. private:
  51. Vector<Operation> recorded_operations_;
  52. };
  53. class PrintContextTest : public RenderingTest {
  54. protected:
  55. explicit PrintContextTest(LocalFrameClient* local_frame_client = nullptr)
  56. : RenderingTest(local_frame_client) {}
  57. ~PrintContextTest() override = default;
  58. void SetUp() override {
  59. RenderingTest::SetUp();
  60. print_context_ = new PrintContext(GetDocument().GetFrame());
  61. }
  62. PrintContext& GetPrintContext() { return *print_context_.Get(); }
  63. void SetBodyInnerHTML(String body_content) {
  64. GetDocument().body()->setAttribute(HTMLNames::styleAttr, "margin: 0");
  65. GetDocument().body()->SetInnerHTMLFromString(body_content);
  66. }
  67. void PrintSinglePage(MockPageContextCanvas& canvas) {
  68. IntRect page_rect(0, 0, kPageWidth, kPageHeight);
  69. GetPrintContext().BeginPrintMode(page_rect.Width(), page_rect.Height());
  70. GetDocument().View()->UpdateAllLifecyclePhases();
  71. PaintRecordBuilder builder;
  72. GraphicsContext& context = builder.Context();
  73. context.SetPrinting(true);
  74. GetDocument().View()->PaintContents(context, kGlobalPaintPrinting,
  75. page_rect);
  76. {
  77. DrawingRecorder recorder(
  78. context, *GetDocument().GetLayoutView(),
  79. DisplayItem::kPrintedContentDestinationLocations);
  80. GetPrintContext().OutputLinkedDestinations(context, page_rect);
  81. }
  82. builder.EndRecording()->Playback(&canvas);
  83. GetPrintContext().EndPrintMode();
  84. }
  85. static String AbsoluteBlockHtmlForLink(int x,
  86. int y,
  87. int width,
  88. int height,
  89. const char* url,
  90. const char* children = nullptr) {
  91. TextStream ts;
  92. ts << "<a style='position: absolute; left: " << x << "px; top: " << y
  93. << "px; width: " << width << "px; height: " << height << "px' href='"
  94. << url << "'>" << (children ? children : url) << "</a>";
  95. return ts.Release();
  96. }
  97. static String InlineHtmlForLink(const char* url,
  98. const char* children = nullptr) {
  99. TextStream ts;
  100. ts << "<a href='" << url << "'>" << (children ? children : url) << "</a>";
  101. return ts.Release();
  102. }
  103. static String HtmlForAnchor(int x,
  104. int y,
  105. const char* name,
  106. const char* text_content) {
  107. TextStream ts;
  108. ts << "<a name='" << name << "' style='position: absolute; left: " << x
  109. << "px; top: " << y << "px'>" << text_content << "</a>";
  110. return ts.Release();
  111. }
  112. private:
  113. std::unique_ptr<DummyPageHolder> page_holder_;
  114. Persistent<PrintContext> print_context_;
  115. };
  116. class PrintContextFrameTest : public PrintContextTest {
  117. public:
  118. PrintContextFrameTest()
  119. : PrintContextTest(SingleChildLocalFrameClient::Create()) {}
  120. };
  121. #define EXPECT_SKRECT_EQ(expectedX, expectedY, expectedWidth, expectedHeight, \
  122. actualRect) \
  123. EXPECT_EQ(expectedX, actualRect.x()); \
  124. EXPECT_EQ(expectedY, actualRect.y()); \
  125. EXPECT_EQ(expectedWidth, actualRect.width()); \
  126. EXPECT_EQ(expectedHeight, actualRect.height());
  127. TEST_F(PrintContextTest, LinkTarget) {
  128. MockPageContextCanvas canvas;
  129. SetBodyInnerHTML(
  130. AbsoluteBlockHtmlForLink(50, 60, 70, 80, "http://www.google.com") +
  131. AbsoluteBlockHtmlForLink(150, 160, 170, 180,
  132. "http://www.google.com#fragment"));
  133. PrintSinglePage(canvas);
  134. const Vector<MockPageContextCanvas::Operation>& operations =
  135. canvas.RecordedOperations();
  136. ASSERT_EQ(2u, operations.size());
  137. EXPECT_EQ(MockPageContextCanvas::kDrawRect, operations[0].type);
  138. EXPECT_SKRECT_EQ(50, 60, 70, 80, operations[0].rect);
  139. EXPECT_EQ(MockPageContextCanvas::kDrawRect, operations[1].type);
  140. EXPECT_SKRECT_EQ(150, 160, 170, 180, operations[1].rect);
  141. }
  142. TEST_F(PrintContextTest, LinkTargetUnderAnonymousBlockBeforeBlock) {
  143. GetDocument().SetCompatibilityMode(Document::kQuirksMode);
  144. MockPageContextCanvas canvas;
  145. SetBodyInnerHTML("<div style='padding-top: 50px'>" +
  146. InlineHtmlForLink("http://www.google.com",
  147. "<img style='width: 111; height: 10'>") +
  148. "<div> " +
  149. InlineHtmlForLink("http://www.google1.com",
  150. "<img style='width: 122; height: 20'>") +
  151. "</div>" + "</div>");
  152. PrintSinglePage(canvas);
  153. const Vector<MockPageContextCanvas::Operation>& operations =
  154. canvas.RecordedOperations();
  155. ASSERT_EQ(2u, operations.size());
  156. EXPECT_EQ(MockPageContextCanvas::kDrawRect, operations[0].type);
  157. EXPECT_SKRECT_EQ(0, 50, 111, 10, operations[0].rect);
  158. EXPECT_EQ(MockPageContextCanvas::kDrawRect, operations[1].type);
  159. EXPECT_SKRECT_EQ(0, 60, 122, 20, operations[1].rect);
  160. }
  161. TEST_F(PrintContextTest, LinkTargetContainingABlock) {
  162. GetDocument().SetCompatibilityMode(Document::kQuirksMode);
  163. MockPageContextCanvas canvas;
  164. SetBodyInnerHTML(
  165. "<div style='padding-top: 50px'>" +
  166. InlineHtmlForLink("http://www.google2.com",
  167. "<div style='width:133; height: 30'>BLOCK</div>") +
  168. "</div>");
  169. PrintSinglePage(canvas);
  170. const Vector<MockPageContextCanvas::Operation>& operations =
  171. canvas.RecordedOperations();
  172. ASSERT_EQ(1u, operations.size());
  173. EXPECT_EQ(MockPageContextCanvas::kDrawRect, operations[0].type);
  174. EXPECT_SKRECT_EQ(0, 50, 133, 30, operations[0].rect);
  175. }
  176. TEST_F(PrintContextTest, LinkTargetUnderInInlines) {
  177. MockPageContextCanvas canvas;
  178. SetBodyInnerHTML(
  179. "<span><b><i><img style='width: 40px; height: 40px'><br>" +
  180. InlineHtmlForLink("http://www.google3.com",
  181. "<img style='width: 144px; height: 40px'>") +
  182. "</i></b></span>");
  183. PrintSinglePage(canvas);
  184. const Vector<MockPageContextCanvas::Operation>& operations =
  185. canvas.RecordedOperations();
  186. ASSERT_EQ(1u, operations.size());
  187. EXPECT_EQ(MockPageContextCanvas::kDrawRect, operations[0].type);
  188. EXPECT_SKRECT_EQ(0, 40, 144, 40, operations[0].rect);
  189. }
  190. TEST_F(PrintContextTest, LinkTargetUnderRelativelyPositionedInline) {
  191. MockPageContextCanvas canvas;
  192. SetBodyInnerHTML(
  193. + "<span style='position: relative; top: 50px; left: 50px'><b><i><img style='width: 1px; height: 40px'><br>"
  194. + InlineHtmlForLink("http://www.google3.com", "<img style='width: 155px; height: 50px'>")
  195. + "</i></b></span>");
  196. PrintSinglePage(canvas);
  197. const Vector<MockPageContextCanvas::Operation>& operations =
  198. canvas.RecordedOperations();
  199. ASSERT_EQ(1u, operations.size());
  200. EXPECT_EQ(MockPageContextCanvas::kDrawRect, operations[0].type);
  201. EXPECT_SKRECT_EQ(50, 90, 155, 50, operations[0].rect);
  202. }
  203. TEST_F(PrintContextTest, LinkTargetSvg) {
  204. MockPageContextCanvas canvas;
  205. SetBodyInnerHTML(R"HTML(
  206. <svg width='100' height='100'>
  207. <a xlink:href='http://www.w3.org'><rect x='20' y='20' width='50'
  208. height='50'/></a>
  209. <text x='10' y='90'><a
  210. xlink:href='http://www.google.com'><tspan>google</tspan></a></text>
  211. </svg>
  212. )HTML");
  213. PrintSinglePage(canvas);
  214. const Vector<MockPageContextCanvas::Operation>& operations =
  215. canvas.RecordedOperations();
  216. ASSERT_EQ(2u, operations.size());
  217. EXPECT_EQ(MockPageContextCanvas::kDrawRect, operations[0].type);
  218. EXPECT_SKRECT_EQ(20, 20, 50, 50, operations[0].rect);
  219. EXPECT_EQ(MockPageContextCanvas::kDrawRect, operations[1].type);
  220. EXPECT_EQ(10, operations[1].rect.x());
  221. EXPECT_GE(90, operations[1].rect.y());
  222. }
  223. TEST_F(PrintContextTest, LinkedTarget) {
  224. MockPageContextCanvas canvas;
  225. GetDocument().SetBaseURLOverride(KURL("http://a.com/"));
  226. SetBodyInnerHTML(
  227. AbsoluteBlockHtmlForLink(
  228. 50, 60, 70, 80,
  229. "#fragment") // Generates a Link_Named_Dest_Key annotation
  230. + AbsoluteBlockHtmlForLink(150, 160, 170, 180,
  231. "#not-found") // Generates no annotation
  232. +
  233. HtmlForAnchor(250, 260, "fragment",
  234. "fragment") // Generates a Define_Named_Dest_Key annotation
  235. + HtmlForAnchor(350, 360, "fragment-not-used",
  236. "fragment-not-used")); // Generates no annotation
  237. PrintSinglePage(canvas);
  238. const Vector<MockPageContextCanvas::Operation>& operations =
  239. canvas.RecordedOperations();
  240. ASSERT_EQ(2u, operations.size());
  241. EXPECT_EQ(MockPageContextCanvas::kDrawRect, operations[0].type);
  242. EXPECT_SKRECT_EQ(50, 60, 70, 80, operations[0].rect);
  243. EXPECT_EQ(MockPageContextCanvas::kDrawPoint, operations[1].type);
  244. EXPECT_SKRECT_EQ(250, 260, 0, 0, operations[1].rect);
  245. }
  246. TEST_F(PrintContextTest, EmptyLinkedTarget) {
  247. MockPageContextCanvas canvas;
  248. GetDocument().SetBaseURLOverride(KURL("http://a.com/"));
  249. SetBodyInnerHTML(AbsoluteBlockHtmlForLink(50, 60, 70, 80, "#fragment") +
  250. HtmlForAnchor(250, 260, "fragment", ""));
  251. PrintSinglePage(canvas);
  252. const Vector<MockPageContextCanvas::Operation>& operations =
  253. canvas.RecordedOperations();
  254. ASSERT_EQ(2u, operations.size());
  255. EXPECT_EQ(MockPageContextCanvas::kDrawRect, operations[0].type);
  256. EXPECT_SKRECT_EQ(50, 60, 70, 80, operations[0].rect);
  257. EXPECT_EQ(MockPageContextCanvas::kDrawPoint, operations[1].type);
  258. EXPECT_SKRECT_EQ(250, 260, 0, 0, operations[1].rect);
  259. }
  260. TEST_F(PrintContextTest, LinkTargetBoundingBox) {
  261. MockPageContextCanvas canvas;
  262. SetBodyInnerHTML(
  263. AbsoluteBlockHtmlForLink(50, 60, 70, 20, "http://www.google.com",
  264. "<img style='width: 200px; height: 100px'>"));
  265. PrintSinglePage(canvas);
  266. const Vector<MockPageContextCanvas::Operation>& operations =
  267. canvas.RecordedOperations();
  268. ASSERT_EQ(1u, operations.size());
  269. EXPECT_EQ(MockPageContextCanvas::kDrawRect, operations[0].type);
  270. EXPECT_SKRECT_EQ(50, 60, 200, 100, operations[0].rect);
  271. }
  272. TEST_F(PrintContextFrameTest, WithSubframe) {
  273. GetDocument().SetBaseURLOverride(KURL("http://a.com/"));
  274. SetBodyInnerHTML(R"HTML(
  275. <style>::-webkit-scrollbar { display: none }</style>
  276. <iframe src='http://b.com/' width='500' height='500'
  277. style='border-width: 5px; margin: 5px; position: absolute; top: 90px;
  278. left: 90px'></iframe>
  279. )HTML");
  280. SetChildFrameHTML(
  281. AbsoluteBlockHtmlForLink(50, 60, 70, 80, "#fragment") +
  282. AbsoluteBlockHtmlForLink(150, 160, 170, 180, "http://www.google.com") +
  283. AbsoluteBlockHtmlForLink(250, 260, 270, 280,
  284. "http://www.google.com#fragment"));
  285. MockPageContextCanvas canvas;
  286. PrintSinglePage(canvas);
  287. const Vector<MockPageContextCanvas::Operation>& operations =
  288. canvas.RecordedOperations();
  289. ASSERT_EQ(2u, operations.size());
  290. EXPECT_EQ(MockPageContextCanvas::kDrawRect, operations[0].type);
  291. EXPECT_SKRECT_EQ(250, 260, 170, 180, operations[0].rect);
  292. EXPECT_EQ(MockPageContextCanvas::kDrawRect, operations[1].type);
  293. EXPECT_SKRECT_EQ(350, 360, 270, 280, operations[1].rect);
  294. }
  295. TEST_F(PrintContextFrameTest, WithScrolledSubframe) {
  296. GetDocument().SetBaseURLOverride(KURL("http://a.com/"));
  297. SetBodyInnerHTML(R"HTML(
  298. <style>::-webkit-scrollbar { display: none }</style>
  299. <iframe src='http://b.com/' width='500' height='500'
  300. style='border-width: 5px; margin: 5px; position: absolute; top: 90px;
  301. left: 90px'></iframe>
  302. )HTML");
  303. SetChildFrameHTML(
  304. AbsoluteBlockHtmlForLink(10, 10, 20, 20, "http://invisible.com") +
  305. AbsoluteBlockHtmlForLink(50, 60, 70, 80, "http://partly.visible.com") +
  306. AbsoluteBlockHtmlForLink(150, 160, 170, 180, "http://www.google.com") +
  307. AbsoluteBlockHtmlForLink(250, 260, 270, 280,
  308. "http://www.google.com#fragment") +
  309. AbsoluteBlockHtmlForLink(850, 860, 70, 80,
  310. "http://another.invisible.com"));
  311. ChildDocument().domWindow()->scrollTo(100, 100);
  312. MockPageContextCanvas canvas;
  313. PrintSinglePage(canvas);
  314. const Vector<MockPageContextCanvas::Operation>& operations =
  315. canvas.RecordedOperations();
  316. ASSERT_EQ(3u, operations.size());
  317. EXPECT_EQ(MockPageContextCanvas::kDrawRect, operations[0].type);
  318. EXPECT_SKRECT_EQ(50, 60, 70, 80,
  319. operations[0].rect); // FIXME: the rect should be clipped.
  320. EXPECT_EQ(MockPageContextCanvas::kDrawRect, operations[1].type);
  321. EXPECT_SKRECT_EQ(150, 160, 170, 180, operations[1].rect);
  322. EXPECT_EQ(MockPageContextCanvas::kDrawRect, operations[2].type);
  323. EXPECT_SKRECT_EQ(250, 260, 270, 280, operations[2].rect);
  324. }
  325. } // namespace blink