mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-10-02 11:10:31 +03:00
Cleaner hit testing: removed UISceneNode::overFind() override; UIRoot now has root-scoped child traversal extent for embedded document scenes.
This commit is contained in:
@@ -164,22 +164,21 @@ application UISceneNode
|
||||
`UIScrollView::mContainer` size updates.
|
||||
- Scroll extent measurement resizes `mDocumentLayout` and `mDocumentScene`, while
|
||||
root/html/body layout remains viewport-sized.
|
||||
- Hit testing now uses a root-scoped traversal extent instead of a
|
||||
`UISceneNode::overFind()` compatibility override. `UIRoot` keeps its layout/self-hit
|
||||
bounds viewport-sized, but embedded document scenes can ask it to traverse child
|
||||
hit testing through the measured document extent.
|
||||
- Basic author `@font-face` isolation is implemented and covered by UIWebView tests.
|
||||
- Tests cover the new topology, viewport-vs-extent behavior, scrolling, two-scene
|
||||
style isolation, navigation supersession, and a resize metric regression that guards
|
||||
against no-op queued viewport churn rebuilding RichText.
|
||||
against no-op queued viewport churn rebuilding RichText. They also cover document
|
||||
root hit testing below the layout viewport.
|
||||
|
||||
### Pending / Follow-Up
|
||||
|
||||
- **Cleaner hit-test bounds model.** The current implementation overrides
|
||||
`UISceneNode::overFind()` for scenes with an explicit layout viewport. This is a
|
||||
narrow compatibility hook: when the viewport-sized `mRoot` rejects a point, the scene
|
||||
searches root children directly so visible scrolled document descendants can still be
|
||||
hit. The cleaner long-term shape is to split layout bounds from hit-test traversal
|
||||
bounds, likely on `UIRoot` or `Node`, so root can remain the layout viewport while
|
||||
hit testing can intentionally traverse visible overflow without a `UISceneNode`
|
||||
special case.
|
||||
- **Author `@font-face` isolation and cleanup** still needs the full scene-local alias
|
||||
registry and navigation cleanup described in Phase 5.
|
||||
- **Author `@font-face` cleanup audit** should verify navigation/destruction cleanup
|
||||
for scene-local aliases and loaded font resources. The basic scene-local isolation
|
||||
path is implemented and tested.
|
||||
- **Subresource lifetime coverage** should be completed for every async path described
|
||||
in Phase 6, including deferred CSS, fonts, images, redirects, cookies, and destruction.
|
||||
- **Example and documentation integration** should be completed after the code shape
|
||||
@@ -477,6 +476,12 @@ two-web-view isolation tests pass:
|
||||
projects/scripts/xvfb-run-eepp bin/unit_tests/eepp-unit_tests-debug
|
||||
```
|
||||
|
||||
Current verification status:
|
||||
|
||||
- Focused `UISceneNode.*` and `UIWebView.*` suites pass through
|
||||
`projects/scripts/xvfb-run-eepp`.
|
||||
- The full native Linux unit-test suite has been run and passes.
|
||||
|
||||
---
|
||||
|
||||
## Completion Criteria
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
# UIWebView Document Scene Isolation Plan
|
||||
|
||||
> Status: PROPOSED - investigated against the current `UIWebView`, `UISceneNode`,
|
||||
> `UIScrollView`, HTML loading, and nested-scene behavior.
|
||||
> Status: IMPLEMENTED WITH FOLLOW-UPS - the owned document scene, real scroll-target
|
||||
> layout widget, viewport/extent split, root-scoped hit-test traversal, and focused
|
||||
> UIWebView coverage are implemented. Remaining work is cleanup/audit coverage for
|
||||
> async subresources, examples/docs, and fixed/sticky acceptance tests.
|
||||
|
||||
## Goal
|
||||
|
||||
@@ -613,6 +615,12 @@ projects/scripts/xvfb-run-eepp bin/unit_tests/eepp-unit_tests-debug
|
||||
Run it after the focused isolation, scrolling, positioned-layout, media-query, and nested-scene
|
||||
tests pass.
|
||||
|
||||
Current verification status:
|
||||
|
||||
- Focused `UISceneNode.*` and `UIWebView.*` suites pass through
|
||||
`projects/scripts/xvfb-run-eepp`.
|
||||
- The full native Linux unit-test suite has been run and passes.
|
||||
|
||||
## Phase Backup Stashes
|
||||
|
||||
Each implementation phase must end with a persistent Git stash backup after that phase's focused
|
||||
|
||||
@@ -16,10 +16,24 @@ class EE_API UIRoot : public UIWidget {
|
||||
|
||||
virtual std::vector<PropertyId> getPropertiesImplemented() const;
|
||||
|
||||
Node* overFind( const Vector2f& point );
|
||||
|
||||
void setChildHitTestTraversalPixelsSize( const Sizef& size );
|
||||
|
||||
void clearChildHitTestTraversalPixelsSize();
|
||||
|
||||
bool hasChildHitTestTraversalPixelsSize() const;
|
||||
|
||||
const Sizef& getChildHitTestTraversalPixelsSize() const;
|
||||
|
||||
protected:
|
||||
UIRoot();
|
||||
|
||||
bool childHitTestTraversalContains( const Vector2f& point );
|
||||
|
||||
Color mDroppableHoveringColor{ Color::Transparent };
|
||||
Sizef mChildHitTestTraversalPixelsSize;
|
||||
bool mHasChildHitTestTraversalPixelsSize{ false };
|
||||
};
|
||||
|
||||
}} // namespace EE::UI
|
||||
|
||||
@@ -28,9 +28,9 @@ class UIIconThemeManager;
|
||||
class UIEventDispatcher;
|
||||
class UIWidget;
|
||||
class UIWindow;
|
||||
class UIWidget;
|
||||
class UILayout;
|
||||
class UIIcon;
|
||||
class UIRoot;
|
||||
|
||||
struct NavigationRequest {
|
||||
URI uri;
|
||||
@@ -715,8 +715,6 @@ class EE_API UISceneNode : public SceneNode {
|
||||
*/
|
||||
void nodeToWorldTranslation( Vector2f& Pos ) const;
|
||||
|
||||
Node* overFind( const Vector2f& point );
|
||||
|
||||
/**
|
||||
* @brief Reloads the UI styles.
|
||||
*
|
||||
@@ -837,7 +835,7 @@ class EE_API UISceneNode : public SceneNode {
|
||||
friend class EE::UI::UIWindow;
|
||||
friend class EE::UI::UIWidget;
|
||||
|
||||
UIWidget* mRoot{ nullptr };
|
||||
UIRoot* mRoot{ nullptr };
|
||||
Sizef mDpSize;
|
||||
Uint32 mFlags;
|
||||
Translator mTranslator;
|
||||
@@ -1113,6 +1111,8 @@ class EE_API UISceneNode : public SceneNode {
|
||||
URI getURIFromURL( const URI& url ) const;
|
||||
|
||||
void updateStyleSheet( bool forceReloadStyle = true );
|
||||
|
||||
void updateRootHitTestTraversalBounds();
|
||||
};
|
||||
|
||||
}} // namespace EE::UI
|
||||
|
||||
@@ -8,6 +8,84 @@ UIRoot* UIRoot::New() {
|
||||
|
||||
UIRoot::UIRoot() : UIWidget( ":root" ) {}
|
||||
|
||||
Node* UIRoot::overFind( const Vector2f& point ) {
|
||||
if ( !mHasChildHitTestTraversalPixelsSize )
|
||||
return UIWidget::overFind( point );
|
||||
|
||||
Node* pOver = nullptr;
|
||||
|
||||
if ( ( mNodeFlags & NODE_FLAG_OVER_FIND_ALLOWED ) && mEnabled && mVisible ) {
|
||||
updateWorldPolygon();
|
||||
|
||||
const bool selfHit = mWorldBounds.contains( point ) && mPoly.pointInside( point );
|
||||
if ( selfHit || childHitTestTraversalContains( point ) ) {
|
||||
Node* child = getLastChild();
|
||||
while ( nullptr != child ) {
|
||||
Node* childOver = child->overFind( point );
|
||||
if ( nullptr != childOver ) {
|
||||
pOver = childOver;
|
||||
break;
|
||||
}
|
||||
child = child->getPrevNode();
|
||||
}
|
||||
|
||||
if ( nullptr != pOver || selfHit ) {
|
||||
writeNodeFlag( NODE_FLAG_MOUSEOVER_ME_OR_CHILD, 1 );
|
||||
mSceneNode->addMouseOverNode( this );
|
||||
}
|
||||
|
||||
if ( nullptr == pOver && selfHit )
|
||||
pOver = this;
|
||||
}
|
||||
}
|
||||
|
||||
return pOver;
|
||||
}
|
||||
|
||||
void UIRoot::setChildHitTestTraversalPixelsSize( const Sizef& size ) {
|
||||
if ( mHasChildHitTestTraversalPixelsSize && mChildHitTestTraversalPixelsSize == size )
|
||||
return;
|
||||
|
||||
mChildHitTestTraversalPixelsSize = size;
|
||||
mHasChildHitTestTraversalPixelsSize = true;
|
||||
}
|
||||
|
||||
void UIRoot::clearChildHitTestTraversalPixelsSize() {
|
||||
if ( !mHasChildHitTestTraversalPixelsSize )
|
||||
return;
|
||||
|
||||
mChildHitTestTraversalPixelsSize = Sizef::Zero;
|
||||
mHasChildHitTestTraversalPixelsSize = false;
|
||||
}
|
||||
|
||||
bool UIRoot::hasChildHitTestTraversalPixelsSize() const {
|
||||
return mHasChildHitTestTraversalPixelsSize;
|
||||
}
|
||||
|
||||
const Sizef& UIRoot::getChildHitTestTraversalPixelsSize() const {
|
||||
return mChildHitTestTraversalPixelsSize;
|
||||
}
|
||||
|
||||
bool UIRoot::childHitTestTraversalContains( const Vector2f& point ) {
|
||||
updateWorldPolygon();
|
||||
|
||||
Polygon2f traversalPoly = Polygon2f( Rectf(
|
||||
mScreenPos.x, mScreenPos.y, mScreenPos.x + mChildHitTestTraversalPixelsSize.getWidth(),
|
||||
mScreenPos.y + mChildHitTestTraversalPixelsSize.getHeight() ) );
|
||||
traversalPoly.rotate( getRotation(), getRotationCenter() );
|
||||
traversalPoly.scale( getScale(), getScaleCenter() );
|
||||
|
||||
Node* parent = getParent();
|
||||
while ( parent ) {
|
||||
traversalPoly.rotate( parent->getRotation(), parent->getRotationCenter() );
|
||||
traversalPoly.scale( parent->getScale(), parent->getScaleCenter() );
|
||||
parent = parent->getParent();
|
||||
}
|
||||
|
||||
const Rectf traversalWorldBounds = traversalPoly.getBounds();
|
||||
return traversalWorldBounds.contains( point ) && traversalPoly.pointInside( point );
|
||||
}
|
||||
|
||||
std::string UIRoot::getPropertyString( const PropertyDefinition* propertyDef,
|
||||
const Uint32& propertyIndex ) const {
|
||||
if ( NULL == propertyDef )
|
||||
|
||||
+17
-48
@@ -179,54 +179,6 @@ void UISceneNode::nodeToWorldTranslation( Vector2f& Pos ) const {
|
||||
}
|
||||
}
|
||||
|
||||
Node* UISceneNode::overFind( const Vector2f& point ) {
|
||||
Node* pOver = NULL;
|
||||
|
||||
if ( ( mNodeFlags & NODE_FLAG_OVER_FIND_ALLOWED ) && mEnabled && mVisible ) {
|
||||
updateWorldPolygon();
|
||||
|
||||
if ( mWorldBounds.contains( point ) && mPoly.pointInside( point ) ) {
|
||||
writeNodeFlag( NODE_FLAG_MOUSEOVER_ME_OR_CHILD, 1 );
|
||||
mSceneNode->addMouseOverNode( this );
|
||||
|
||||
Node* child = getLastChild();
|
||||
|
||||
while ( NULL != child ) {
|
||||
Node* childOver = child->overFind( point );
|
||||
|
||||
if ( NULL == childOver && child == mRoot && mHasLayoutViewportPixelsSize ) {
|
||||
mRoot->updateWorldPolygon();
|
||||
mRoot->writeNodeFlag( NODE_FLAG_MOUSEOVER_ME_OR_CHILD, 1 );
|
||||
mSceneNode->addMouseOverNode( mRoot );
|
||||
|
||||
Node* rootChild = mRoot->getLastChild();
|
||||
while ( NULL != rootChild ) {
|
||||
childOver = rootChild->overFind( point );
|
||||
if ( NULL != childOver )
|
||||
break;
|
||||
rootChild = rootChild->getPrevNode();
|
||||
}
|
||||
|
||||
if ( NULL == childOver )
|
||||
childOver = mRoot;
|
||||
}
|
||||
|
||||
if ( NULL != childOver ) {
|
||||
pOver = childOver;
|
||||
break;
|
||||
}
|
||||
|
||||
child = child->getPrevNode();
|
||||
}
|
||||
|
||||
if ( NULL == pOver )
|
||||
pOver = this;
|
||||
}
|
||||
}
|
||||
|
||||
return pOver;
|
||||
}
|
||||
|
||||
void UISceneNode::onParentChange() {
|
||||
SceneNode::onParentChange();
|
||||
|
||||
@@ -797,6 +749,7 @@ void UISceneNode::setInternalSize( const Sizef& size ) {
|
||||
mSize = PixelDensity::dpToPx( size );
|
||||
updateCenter();
|
||||
onSizeChange();
|
||||
updateRootHitTestTraversalBounds();
|
||||
sendCommonEvent( Event::OnSizeChange );
|
||||
invalidateDraw();
|
||||
}
|
||||
@@ -849,6 +802,7 @@ void UISceneNode::setViewportPixelsSize( const Sizef& size ) {
|
||||
mViewportPixelsSize = size;
|
||||
mHasViewportPixelsSize = true;
|
||||
mRoot->setPixelsSize( getRootPixelsSize() );
|
||||
updateRootHitTestTraversalBounds();
|
||||
onViewportPixelsSizeChange();
|
||||
}
|
||||
|
||||
@@ -858,6 +812,7 @@ void UISceneNode::clearViewportPixelsSize() {
|
||||
|
||||
mHasViewportPixelsSize = false;
|
||||
mRoot->setPixelsSize( getRootPixelsSize() );
|
||||
updateRootHitTestTraversalBounds();
|
||||
onViewportPixelsSizeChange();
|
||||
}
|
||||
|
||||
@@ -878,6 +833,7 @@ void UISceneNode::setLayoutViewportPixelsSize( const Sizef& size ) {
|
||||
mLayoutViewportPixelsSize = size;
|
||||
mHasLayoutViewportPixelsSize = true;
|
||||
mRoot->setPixelsSize( getRootPixelsSize() );
|
||||
updateRootHitTestTraversalBounds();
|
||||
sendMsg( this, NodeMessage::WindowResize );
|
||||
}
|
||||
|
||||
@@ -887,6 +843,7 @@ void UISceneNode::clearLayoutViewportPixelsSize() {
|
||||
|
||||
mHasLayoutViewportPixelsSize = false;
|
||||
mRoot->setPixelsSize( getRootPixelsSize() );
|
||||
updateRootHitTestTraversalBounds();
|
||||
sendMsg( this, NodeMessage::WindowResize );
|
||||
}
|
||||
|
||||
@@ -1695,11 +1652,23 @@ void UISceneNode::setInternalPixelsSize( const Sizef& size ) {
|
||||
mNodeFlags |= NODE_FLAG_POLYGON_DIRTY;
|
||||
updateCenter();
|
||||
onSizeChange();
|
||||
updateRootHitTestTraversalBounds();
|
||||
sendCommonEvent( Event::OnSizeChange );
|
||||
invalidateDraw();
|
||||
}
|
||||
}
|
||||
|
||||
void UISceneNode::updateRootHitTestTraversalBounds() {
|
||||
if ( !mRoot )
|
||||
return;
|
||||
|
||||
if ( mHasLayoutViewportPixelsSize ) {
|
||||
mRoot->setChildHitTestTraversalPixelsSize( mSize );
|
||||
} else {
|
||||
mRoot->clearChildHitTestTraversalPixelsSize();
|
||||
}
|
||||
}
|
||||
|
||||
Uint32 UISceneNode::onKeyDown( const KeyEvent& event ) {
|
||||
std::string cmd = mKeyBindings.getCommandFromKeyBind( { event.getKeyCode(), event.getMod() } );
|
||||
if ( !cmd.empty() ) {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <eepp/scene/scenemanager.hpp>
|
||||
#include <eepp/system/filesystem.hpp>
|
||||
#include <eepp/system/sys.hpp>
|
||||
#include <eepp/ui/uiroot.hpp>
|
||||
#include <eepp/ui/uiscenenode.hpp>
|
||||
#include <eepp/ui/uithememanager.hpp>
|
||||
#include <eepp/ui/uiwidget.hpp>
|
||||
@@ -150,6 +151,44 @@ UTEST( UISceneNode, EmbeddedSceneCanKeepContentDrivenExtent ) {
|
||||
Engine::destroySingleton();
|
||||
}
|
||||
|
||||
UTEST( UISceneNode, LayoutViewportRootTraversesDocumentExtentForHitTesting ) {
|
||||
Engine::instance()->createWindow( WindowSettings( 1024, 768, "Embedded Scene Hit Test Bounds",
|
||||
WindowStyle::Default, WindowBackend::Default,
|
||||
32, {}, 1, false, true ),
|
||||
ContextSettings( false, 0, 0, GLv_default, true, false ) );
|
||||
|
||||
UISceneNode* hostScene = init_test_scene_node();
|
||||
UIWidget* host = UIWidget::New();
|
||||
host->setPixelsSize( 800, 600 );
|
||||
host->setParent( hostScene->getRoot() );
|
||||
|
||||
UISceneNode* embeddedScene = UISceneNode::New();
|
||||
embeddedScene->setFollowParentSize( false );
|
||||
embeddedScene->setParent( host );
|
||||
embeddedScene->setPixelsSize( 800, 1000 );
|
||||
embeddedScene->setLayoutViewportPixelsSize( Sizef( 800, 300 ) );
|
||||
|
||||
UIWidget* target = UIWidget::New();
|
||||
target->setId( "below-layout-viewport" );
|
||||
target->setPixelsSize( 100, 50 );
|
||||
target->setPosition( 10, 900 );
|
||||
target->setParent( embeddedScene->getRoot() );
|
||||
|
||||
UIRoot* embeddedRoot = embeddedScene->getRoot()->asType<UIRoot>();
|
||||
ASSERT_TRUE( embeddedRoot != nullptr );
|
||||
ASSERT_TRUE( embeddedRoot->hasChildHitTestTraversalPixelsSize() );
|
||||
EXPECT_NEAR( embeddedScene->getRoot()->getPixelsSize().getHeight(), 300.f, 0.5f );
|
||||
EXPECT_NEAR( embeddedRoot->getChildHitTestTraversalPixelsSize().getHeight(), 1000.f, 0.5f );
|
||||
|
||||
Node* hit = embeddedScene->overFind( Vector2f( 20, 920 ) );
|
||||
EXPECT_EQ( hit, target );
|
||||
|
||||
embeddedScene->clearLayoutViewportPixelsSize();
|
||||
EXPECT_FALSE( embeddedRoot->hasChildHitTestTraversalPixelsSize() );
|
||||
|
||||
Engine::destroySingleton();
|
||||
}
|
||||
|
||||
UTEST( UISceneNode, NestedSceneOwnsDescendantSceneAndStyles ) {
|
||||
Engine::instance()->createWindow( WindowSettings( 1024, 768, "Nested Scene Isolation Test",
|
||||
WindowStyle::Default, WindowBackend::Default,
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <eepp/system/filesystem.hpp>
|
||||
#include <eepp/system/sys.hpp>
|
||||
#include <eepp/ui/uilayout.hpp>
|
||||
#include <eepp/ui/uiroot.hpp>
|
||||
#include <eepp/ui/uiscenenode.hpp>
|
||||
#include <eepp/ui/uiscrollbar.hpp>
|
||||
#include <eepp/ui/uithememanager.hpp>
|
||||
@@ -92,6 +93,83 @@ UTEST( UIWebView, OwnedDocumentSceneScrollTarget ) {
|
||||
Engine::destroySingleton();
|
||||
}
|
||||
|
||||
UTEST( UIWebView, DocumentRootHitTestingTraversesScrollableExtent ) {
|
||||
auto win = Engine::instance()->createWindow(
|
||||
WindowSettings( 640, 480, "UIWebView Document Hit Test Bounds", WindowStyle::Default,
|
||||
WindowBackend::Default, 32, {}, 1, false, true ),
|
||||
ContextSettings( false, 0, 0, GLv_default, true, false ) );
|
||||
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
||||
|
||||
FontTrueType* font = FontTrueType::New( "NotoSans-Regular" );
|
||||
font->loadFromFile( "../assets/fonts/NotoSans-Regular.ttf" );
|
||||
ASSERT_TRUE( font != nullptr && font->loaded() );
|
||||
FontFamily::loadFromRegular( font );
|
||||
|
||||
UISceneNode* sceneNode = UISceneNode::New();
|
||||
SceneManager::instance()->add( sceneNode );
|
||||
sceneNode->getUIThemeManager()->setDefaultFont( font );
|
||||
|
||||
UIWebView* webView = UIWebView::New();
|
||||
webView->setParent( sceneNode->getRoot() );
|
||||
webView->setPixelsSize( 400, 300 );
|
||||
webView->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed );
|
||||
webView->getVerticalScrollBar()->setPixelsSize( 15, 300 );
|
||||
webView->getHorizontalScrollBar()->setPixelsSize( 400, 15 );
|
||||
|
||||
const std::string path = Sys::getTempPath() + "eepp_uiwebview_hit_test_extent.html";
|
||||
FileSystem::fileWrite( path, R"html(
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head><style>html, body { margin: 0; padding: 0; }</style></head>
|
||||
<body>
|
||||
<div style="height: 900px"></div>
|
||||
<div id="target" style="width: 220px; height: 100px; background: #abcdef"></div>
|
||||
</body>
|
||||
</html>
|
||||
)html" );
|
||||
webView->loadURI( URI( "file://" + path ) );
|
||||
|
||||
UISceneNode* documentScene = webView->getDocumentSceneNode();
|
||||
ASSERT_TRUE( documentScene != nullptr );
|
||||
|
||||
auto pump = [&]() {
|
||||
for ( int i = 0; i < 30; i++ ) {
|
||||
win->getInput()->update();
|
||||
SceneManager::instance()->update( Seconds( 1.f / 60.f ) );
|
||||
}
|
||||
};
|
||||
pump();
|
||||
|
||||
Node* targetNode = documentScene->getRoot()->find( "target" );
|
||||
ASSERT_TRUE( targetNode != nullptr && targetNode->isWidget() );
|
||||
UIWidget* target = targetNode->asType<UIWidget>();
|
||||
ASSERT_TRUE( webView->getVerticalScrollBar()->isVisible() );
|
||||
UIRoot* documentRoot = documentScene->getRoot()->asType<UIRoot>();
|
||||
ASSERT_TRUE( documentRoot != nullptr );
|
||||
ASSERT_TRUE( documentRoot->hasChildHitTestTraversalPixelsSize() );
|
||||
EXPECT_NEAR( documentScene->getRoot()->getPixelsSize().getHeight(),
|
||||
documentScene->getViewportPixelsSize().getHeight(), 0.5f );
|
||||
EXPECT_NEAR( documentRoot->getChildHitTestTraversalPixelsSize().getHeight(),
|
||||
documentScene->getPixelsSize().getHeight(), 0.5f );
|
||||
|
||||
webView->getVerticalScrollBar()->setValue( 1.f );
|
||||
pump();
|
||||
|
||||
const Rectf targetRect = target->getScreenRect();
|
||||
const Rectf rootRect = documentScene->getRoot()->getScreenRect();
|
||||
const Rectf containerRect = webView->getContainer()->getScreenRect();
|
||||
const Vector2f hitPoint( targetRect.Left + targetRect.getWidth() * 0.5f,
|
||||
targetRect.Top + targetRect.getHeight() * 0.5f );
|
||||
ASSERT_TRUE( containerRect.contains( hitPoint ) );
|
||||
ASSERT_FALSE( rootRect.contains( hitPoint ) );
|
||||
|
||||
Node* hitNode = sceneNode->overFind( hitPoint );
|
||||
ASSERT_TRUE( hitNode != nullptr );
|
||||
EXPECT_TRUE( hitNode == target || target->isParentOf( hitNode ) );
|
||||
|
||||
Engine::destroySingleton();
|
||||
}
|
||||
|
||||
UTEST( UIWebView, VerticalScrollbarViewportDoesNotCreateHorizontalScroll ) {
|
||||
auto win = Engine::instance()->createWindow(
|
||||
WindowSettings( 640, 480, "UIWebView Scrollbar Viewport Test", WindowStyle::Default,
|
||||
|
||||
Reference in New Issue
Block a user