| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "base/basictypes.h" | 5 #include "base/basictypes.h" |
| 6 #include "base/logging.h" | 6 #include "base/logging.h" |
| 7 #include "base/memory/scoped_ptr.h" | 7 #include "base/memory/scoped_ptr.h" |
| 8 #include "base/message_loop/message_loop.h" | 8 #include "base/message_loop/message_loop.h" |
| 9 #include "content/browser/renderer_host/input/timeout_monitor.h" | 9 #include "content/browser/renderer_host/input/timeout_monitor.h" |
| 10 #include "content/browser/renderer_host/input/touch_event_queue.h" | 10 #include "content/browser/renderer_host/input/touch_event_queue.h" |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 118 } | 118 } |
| 119 | 119 |
| 120 void SetFollowupEvent(const WebGestureEvent& event) { | 120 void SetFollowupEvent(const WebGestureEvent& event) { |
| 121 followup_gesture_event_.reset(new WebGestureEvent(event)); | 121 followup_gesture_event_.reset(new WebGestureEvent(event)); |
| 122 } | 122 } |
| 123 | 123 |
| 124 void SetSyncAckResult(InputEventAckState sync_ack_result) { | 124 void SetSyncAckResult(InputEventAckState sync_ack_result) { |
| 125 sync_ack_result_.reset(new InputEventAckState(sync_ack_result)); | 125 sync_ack_result_.reset(new InputEventAckState(sync_ack_result)); |
| 126 } | 126 } |
| 127 | 127 |
| 128 void PressTouchPoint(int x, int y) { | 128 void PressTouchPoint(float x, float y) { |
| 129 touch_event_.PressPoint(x, y); | 129 touch_event_.PressPoint(x, y); |
| 130 SendTouchEvent(); | 130 SendTouchEvent(); |
| 131 } | 131 } |
| 132 | 132 |
| 133 void MoveTouchPoint(int index, int x, int y) { | 133 void MoveTouchPoint(int index, float x, float y) { |
| 134 touch_event_.MovePoint(index, x, y); | 134 touch_event_.MovePoint(index, x, y); |
| 135 SendTouchEvent(); | 135 SendTouchEvent(); |
| 136 } | 136 } |
| 137 | 137 |
| 138 void MoveTouchPoints(int index0, int x0, int y0, int index1, int x1, int y1) { | 138 void MoveTouchPoints(int index0, |
| 139 float x0, |
| 140 float y0, |
| 141 int index1, |
| 142 float x1, |
| 143 float y1) { |
| 139 touch_event_.MovePoint(index0, x0, y0); | 144 touch_event_.MovePoint(index0, x0, y0); |
| 140 touch_event_.MovePoint(index1, x1, y1); | 145 touch_event_.MovePoint(index1, x1, y1); |
| 141 SendTouchEvent(); | 146 SendTouchEvent(); |
| 142 } | 147 } |
| 143 | 148 |
| 144 void ReleaseTouchPoint(int index) { | 149 void ReleaseTouchPoint(int index) { |
| 145 touch_event_.ReleasePoint(index); | 150 touch_event_.ReleasePoint(index); |
| 146 SendTouchEvent(); | 151 SendTouchEvent(); |
| 147 } | 152 } |
| 148 | 153 |
| (...skipping 1201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1350 EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, acked_event_state()); | 1355 EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, acked_event_state()); |
| 1351 | 1356 |
| 1352 MoveTouchPoint(0, -kHalfSlopLengthDips, 0); | 1357 MoveTouchPoint(0, -kHalfSlopLengthDips, 0); |
| 1353 EXPECT_EQ(0U, queued_event_count()); | 1358 EXPECT_EQ(0U, queued_event_count()); |
| 1354 EXPECT_EQ(0U, GetAndResetSentEventCount()); | 1359 EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| 1355 EXPECT_EQ(1U, GetAndResetAckedEventCount()); | 1360 EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| 1356 EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, acked_event_state()); | 1361 EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, acked_event_state()); |
| 1357 | 1362 |
| 1358 // As soon as a TouchMove exceeds the (Euclidean) distance, no more | 1363 // As soon as a TouchMove exceeds the (Euclidean) distance, no more |
| 1359 // TouchMove's should be suppressed. | 1364 // TouchMove's should be suppressed. |
| 1360 // TODO(jdduke): Remove ceil with adoption of floating point touch coords, | |
| 1361 // crbug/336807. | |
| 1362 const double kFortyFiveDegreeSlopLengthXY = | 1365 const double kFortyFiveDegreeSlopLengthXY = |
| 1363 std::ceil(kSlopLengthDips * std::sqrt(2.) / 2.); | 1366 kSlopLengthDips * std::sqrt(2.) / 2.; |
| 1364 MoveTouchPoint(0, kFortyFiveDegreeSlopLengthXY + .1, | 1367 MoveTouchPoint(0, kFortyFiveDegreeSlopLengthXY + .2, |
| 1365 kFortyFiveDegreeSlopLengthXY + .1); | 1368 kFortyFiveDegreeSlopLengthXY + .2); |
| 1366 EXPECT_EQ(1U, queued_event_count()); | 1369 EXPECT_EQ(1U, queued_event_count()); |
| 1367 EXPECT_EQ(1U, GetAndResetSentEventCount()); | 1370 EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| 1368 EXPECT_EQ(0U, GetAndResetAckedEventCount()); | 1371 EXPECT_EQ(0U, GetAndResetAckedEventCount()); |
| 1369 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 1372 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| 1370 EXPECT_EQ(1U, GetAndResetAckedEventCount()); | 1373 EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| 1371 | 1374 |
| 1372 // Even TouchMove's within the original slop region should now be forwarded. | 1375 // Even TouchMove's within the original slop region should now be forwarded. |
| 1373 MoveTouchPoint(0, 0, 0); | 1376 MoveTouchPoint(0, 0, 0); |
| 1374 EXPECT_EQ(1U, queued_event_count()); | 1377 EXPECT_EQ(1U, queued_event_count()); |
| 1375 EXPECT_EQ(1U, GetAndResetSentEventCount()); | 1378 EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| 1376 EXPECT_EQ(0U, GetAndResetAckedEventCount()); | 1379 EXPECT_EQ(0U, GetAndResetAckedEventCount()); |
| 1377 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 1380 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| 1378 EXPECT_EQ(1U, GetAndResetAckedEventCount()); | 1381 EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| 1379 | 1382 |
| 1380 // A new touch sequence should reset suppression. | 1383 // A new touch sequence should reset suppression. |
| 1381 ReleaseTouchPoint(0); | 1384 ReleaseTouchPoint(0); |
| 1382 PressTouchPoint(0, 0); | 1385 PressTouchPoint(0, 0); |
| 1383 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 1386 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| 1384 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 1387 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| 1385 ASSERT_EQ(2U, GetAndResetSentEventCount()); | 1388 ASSERT_EQ(2U, GetAndResetSentEventCount()); |
| 1386 ASSERT_EQ(2U, GetAndResetAckedEventCount()); | 1389 ASSERT_EQ(2U, GetAndResetAckedEventCount()); |
| 1387 ASSERT_EQ(0U, queued_event_count()); | 1390 ASSERT_EQ(0U, queued_event_count()); |
| 1388 | 1391 |
| 1389 // The slop region is boundary-exclusive. | 1392 // The slop region is boundary-inclusive. |
| 1390 // TODO(jdduke): Change to inclusive upon resolving crbug.com/336807. | |
| 1391 MoveTouchPoint(0, kSlopLengthDips - 1., 0); | 1393 MoveTouchPoint(0, kSlopLengthDips - 1., 0); |
| 1392 EXPECT_EQ(0U, queued_event_count()); | 1394 EXPECT_EQ(0U, queued_event_count()); |
| 1393 EXPECT_EQ(0U, GetAndResetSentEventCount()); | 1395 EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| 1394 EXPECT_EQ(1U, GetAndResetAckedEventCount()); | 1396 EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| 1395 | 1397 |
| 1396 MoveTouchPoint(0, kSlopLengthDips, 0); | 1398 MoveTouchPoint(0, kSlopLengthDips, 0); |
| 1397 EXPECT_EQ(1U, queued_event_count()); | 1399 EXPECT_EQ(0U, queued_event_count()); |
| 1398 EXPECT_EQ(1U, GetAndResetSentEventCount()); | 1400 EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| 1399 EXPECT_EQ(0U, GetAndResetAckedEventCount()); | 1401 EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| 1400 } | 1402 } |
| 1401 | 1403 |
| 1402 // Tests that TouchMove's are not dropped within the slop suppression region if | 1404 // Tests that TouchMove's are not dropped within the slop suppression region if |
| 1403 // the touchstart was consumed. | 1405 // the touchstart was consumed. |
| 1404 TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionAfterTouchConsumed) { | 1406 TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionAfterTouchConsumed) { |
| 1405 const double kSlopLengthDips = 10.; | 1407 const double kSlopLengthDips = 10.; |
| 1406 const double kHalfSlopLengthDips = kSlopLengthDips / 2; | 1408 const double kHalfSlopLengthDips = kSlopLengthDips / 2; |
| 1407 SetUpForTouchMoveSlopTesting(kSlopLengthDips); | 1409 SetUpForTouchMoveSlopTesting(kSlopLengthDips); |
| 1408 | 1410 |
| 1409 // Queue a TouchStart. | 1411 // Queue a TouchStart. |
| 1410 PressTouchPoint(0, 0); | 1412 PressTouchPoint(0, 0); |
| 1411 SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED); | 1413 SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED); |
| 1412 ASSERT_EQ(1U, GetAndResetSentEventCount()); | 1414 ASSERT_EQ(1U, GetAndResetSentEventCount()); |
| 1413 ASSERT_EQ(1U, GetAndResetAckedEventCount()); | 1415 ASSERT_EQ(1U, GetAndResetAckedEventCount()); |
| 1414 | 1416 |
| 1415 // TouchMove's within the region should not be suppressed, as a touch was | 1417 // TouchMove's within the region should not be suppressed, as a touch was |
| 1416 // consumed. | 1418 // consumed. |
| 1417 MoveTouchPoint(0, 0, kHalfSlopLengthDips); | 1419 MoveTouchPoint(0, 0, kHalfSlopLengthDips); |
| 1418 EXPECT_EQ(1U, queued_event_count()); | 1420 EXPECT_EQ(1U, queued_event_count()); |
| 1419 EXPECT_EQ(1U, GetAndResetSentEventCount()); | 1421 EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| 1420 EXPECT_EQ(0U, GetAndResetAckedEventCount()); | 1422 EXPECT_EQ(0U, GetAndResetAckedEventCount()); |
| 1421 } | 1423 } |
| 1422 | 1424 |
| 1423 // Tests that TouchMove's are not dropped due to integral truncation of | 1425 // Tests that TouchMove's are not dropped due to incorrect handling of DPI |
| 1424 // WebTouchPoint coordinates after DPI scaling. | 1426 // scaling. |
| 1425 TEST_F(TouchEventQueueTest, TouchMoveSuppressionWithDIPScaling) { | 1427 TEST_F(TouchEventQueueTest, TouchMoveSuppressionWithDIPScaling) { |
| 1426 const float kSlopLengthPixels = 7.f; | 1428 const float kSlopLengthPixels = 7.f; |
| 1427 const float kDPIScale = 3.f; | 1429 const float kDPIScale = 3.f; |
| 1428 SetUpForTouchMoveSlopTesting(kSlopLengthPixels / kDPIScale); | 1430 SetUpForTouchMoveSlopTesting(kSlopLengthPixels / kDPIScale); |
| 1429 | 1431 |
| 1430 // Queue a TouchStart. | 1432 // Queue a TouchStart. |
| 1431 PressTouchPoint(0, 0); | 1433 PressTouchPoint(0, 0); |
| 1432 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 1434 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| 1433 ASSERT_EQ(1U, GetAndResetSentEventCount()); | 1435 ASSERT_EQ(1U, GetAndResetSentEventCount()); |
| 1434 ASSERT_EQ(1U, GetAndResetAckedEventCount()); | 1436 ASSERT_EQ(1U, GetAndResetAckedEventCount()); |
| 1435 | 1437 |
| 1436 // TouchMove's along the slop boundary should not be suppresed. | 1438 // TouchMove's along the slop boundary should be suppresed. |
| 1437 // TODO(jdduke): These should be suppressed, crbug.com/336807. | |
| 1438 MoveTouchPoint(0, 0, kSlopLengthPixels / kDPIScale); | 1439 MoveTouchPoint(0, 0, kSlopLengthPixels / kDPIScale); |
| 1439 EXPECT_EQ(1U, queued_event_count()); | 1440 EXPECT_EQ(0U, queued_event_count()); |
| 1440 EXPECT_EQ(1U, GetAndResetSentEventCount()); | 1441 EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| 1441 EXPECT_EQ(0U, GetAndResetAckedEventCount()); | 1442 EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| 1442 | 1443 |
| 1443 // Reset the touch sequence. | 1444 // Reset the touch sequence. |
| 1444 ReleaseTouchPoint(0); | 1445 ReleaseTouchPoint(0); |
| 1445 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 1446 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| 1446 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 1447 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| 1447 GetAndResetSentEventCount(); | 1448 GetAndResetSentEventCount(); |
| 1448 GetAndResetAckedEventCount(); | 1449 GetAndResetAckedEventCount(); |
| 1449 | 1450 |
| 1450 // Queue a TouchStart. | 1451 // Queue a TouchStart. |
| 1451 PressTouchPoint(0, 0); | 1452 PressTouchPoint(0, 0); |
| 1452 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 1453 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| 1453 ASSERT_EQ(1U, GetAndResetSentEventCount()); | 1454 ASSERT_EQ(1U, GetAndResetSentEventCount()); |
| 1454 ASSERT_EQ(1U, GetAndResetAckedEventCount()); | 1455 ASSERT_EQ(1U, GetAndResetAckedEventCount()); |
| 1455 | 1456 |
| 1456 // TouchMove's outside the region should not be suppressed. | 1457 // TouchMove's outside the region should not be suppressed. |
| 1457 const float kPixelCoordOutsideSlopRegion = kSlopLengthPixels + 1.f; | 1458 const float kPixelCoordOutsideSlopRegion = kSlopLengthPixels + 0.5f; |
| 1458 MoveTouchPoint(0, 0, kPixelCoordOutsideSlopRegion / kDPIScale); | 1459 MoveTouchPoint(0, 0, kPixelCoordOutsideSlopRegion / kDPIScale); |
| 1459 EXPECT_EQ(1U, queued_event_count()); | 1460 EXPECT_EQ(1U, queued_event_count()); |
| 1460 EXPECT_EQ(1U, GetAndResetSentEventCount()); | 1461 EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| 1461 EXPECT_EQ(0U, GetAndResetAckedEventCount()); | 1462 EXPECT_EQ(0U, GetAndResetAckedEventCount()); |
| 1462 } | 1463 } |
| 1463 | 1464 |
| 1464 | |
| 1465 // Tests that TouchMove's are not dropped if a secondary pointer is present | 1465 // Tests that TouchMove's are not dropped if a secondary pointer is present |
| 1466 // during any movement. | 1466 // during any movement. |
| 1467 TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionAfterMultiTouch) { | 1467 TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionAfterMultiTouch) { |
| 1468 const double kSlopLengthDips = 10.; | 1468 const double kSlopLengthDips = 10.; |
| 1469 const double kHalfSlopLengthDips = kSlopLengthDips / 2; | 1469 const double kHalfSlopLengthDips = kSlopLengthDips / 2; |
| 1470 const double kDoubleSlopLengthDips = 10.; | |
| 1471 SetUpForTouchMoveSlopTesting(kSlopLengthDips); | 1470 SetUpForTouchMoveSlopTesting(kSlopLengthDips); |
| 1472 | 1471 |
| 1473 // Queue a TouchStart. | 1472 // Queue a TouchStart. |
| 1474 PressTouchPoint(0, 0); | 1473 PressTouchPoint(0, 0); |
| 1475 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 1474 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| 1476 ASSERT_EQ(1U, GetAndResetSentEventCount()); | 1475 ASSERT_EQ(1U, GetAndResetSentEventCount()); |
| 1477 ASSERT_EQ(1U, GetAndResetAckedEventCount()); | 1476 ASSERT_EQ(1U, GetAndResetAckedEventCount()); |
| 1478 | 1477 |
| 1479 // TouchMove's within the region should be suppressed. | 1478 // TouchMove's within the region should be suppressed. |
| 1480 MoveTouchPoint(0, 0, kHalfSlopLengthDips); | 1479 MoveTouchPoint(0, 0, kHalfSlopLengthDips); |
| 1481 EXPECT_EQ(0U, queued_event_count()); | 1480 EXPECT_EQ(0U, queued_event_count()); |
| 1482 EXPECT_EQ(0U, GetAndResetSentEventCount()); | 1481 EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| 1483 EXPECT_EQ(1U, GetAndResetAckedEventCount()); | 1482 EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| 1484 | 1483 |
| 1485 // Simulate a secondary pointer press. | 1484 // Simulate a secondary pointer press. |
| 1486 PressTouchPoint(kDoubleSlopLengthDips, 0); | 1485 PressTouchPoint(kSlopLengthDips, 0); |
| 1487 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 1486 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| 1488 EXPECT_EQ(1U, GetAndResetSentEventCount()); | 1487 EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| 1489 EXPECT_EQ(1U, GetAndResetAckedEventCount()); | 1488 EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| 1490 | 1489 |
| 1491 // TouchMove with a secondary pointer should not be suppressed. | 1490 // TouchMove with a secondary pointer should not be suppressed. |
| 1492 MoveTouchPoint(1, kDoubleSlopLengthDips, 0); | 1491 MoveTouchPoint(1, kSlopLengthDips, 0); |
| 1493 EXPECT_EQ(1U, queued_event_count()); | 1492 EXPECT_EQ(1U, queued_event_count()); |
| 1494 EXPECT_EQ(1U, GetAndResetSentEventCount()); | 1493 EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| 1495 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 1494 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| 1496 EXPECT_EQ(1U, GetAndResetAckedEventCount()); | 1495 EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| 1497 | 1496 |
| 1498 // Release the secondary pointer. | 1497 // Release the secondary pointer. |
| 1499 ReleaseTouchPoint(0); | 1498 ReleaseTouchPoint(0); |
| 1500 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 1499 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| 1501 EXPECT_EQ(1U, GetAndResetSentEventCount()); | 1500 EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| 1502 EXPECT_EQ(1U, GetAndResetAckedEventCount()); | 1501 EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1611 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 1610 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| 1612 EXPECT_EQ(1U, GetAndResetSentEventCount()); | 1611 EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| 1613 EXPECT_EQ(1U, GetAndResetAckedEventCount()); | 1612 EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| 1614 MoveTouchPoint(0, 0, 10); | 1613 MoveTouchPoint(0, 0, 10); |
| 1615 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 1614 SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| 1616 EXPECT_EQ(0U, queued_event_count()); | 1615 EXPECT_EQ(0U, queued_event_count()); |
| 1617 EXPECT_EQ(0U, GetAndResetSentEventCount()); | 1616 EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| 1618 } | 1617 } |
| 1619 | 1618 |
| 1620 } // namespace content | 1619 } // namespace content |
| OLD | NEW |