Determining page state/working with frames.

Having problems with building or using CEF's C/C++ APIs? This forum is here to help. Please do not post bug reports or feature requests here.

Determining page state/working with frames.

Postby chillitom » Thu Dec 09, 2010 10:29 am

Hi Marshall et al.

As you know I'm trying to provide a Chromium/CEF based browser control for .Net similar to MSHTML, GeckoFx or Webkit.NET it's going well so far but there are currently two problems that I'm now facing.

I cannot find a good way of notifying users that a page is fully loaded and I cannot find a reliable way to expose frames or determine which frames events are occurring on. This is very important for users that want to programmatically exercise a web site.

Regarding notification that a page is fully loaded, it'd like to be able to inform users at the point that they might safely run scripts against the page or inspect its contents. There doesn't appear to be a way to query a browser or frame for its current state and the HandleLoadStart, HandleLoadEnd methods do not seem to fire at the appropriate times, for instance the HandleLoadEnd event fires several times for the CefBrowser.

Below is some debug output from loading http://www.google.co.uk/search?q=cefsharp

Code: Select all
HandleAfterCreated(CefBrowser:061da4b8)
HandleLoadStart(CefBrowser:0x061da510, CefFrame:0x00000000)
http://www.google.co.uk/search?q=cefsharp
HandleLoadStart(CefBrowser:0x061dac80, CefFrame:0x061da510) FrameName="" MainFrame? True
http://www.google.co.uk/blank.html
http://www.google.co.uk/images/nav_logo29.png
HandleLoadStart(CefBrowser:0x061daf30, CefFrame:0x061dac80) FrameName="wgjf" MainFrame? False
  HandleLoadEnd(CefBrowser:0x061db250, CefFrame:0x061db1f8) FrameName="wgjf" MainFrame? False
http://www.google.co.uk/extern_js/f/CgJlbhICdWsrMEU4ACwrMFo4ACwrMA44ACwrMBc4ACwrMCc4ACwrMDw4ACwrMFE4ACwrMFk4ACwrMAo4AEAdmgICcHMsKzAWOAAsKzAZOAAsKzAlOM-IASwrMCo4CywrMCs4ESwrMDU4ACwrMEA4ACwrMEE4ACwrME04ACwrME44ACwrMFM4ACwrMFQ4ACwrMF84ACwrMGM4ACwrMGk4ACwrMB04AJoCAnBzLCswXDgALCswGDgALCswJjgALIACKpACJw/cDLPAIGguKY.js
  HandleLoadEnd(CefBrowser:0x061db2a8, CefFrame:0x061db250) FrameName="" MainFrame? True
  HandleLoadEnd(CefBrowser:0x061db250, CefFrame:0x00000000)
http://www.google.co.uk/extern_chrome/6354f67d2c0f0c5e.js
HandleLoadStart(CefBrowser:0x061db2a8, CefFrame:0x00000000)
http://www.google.co.uk/compressiontest/gzip.html
HandleLoadStart(CefBrowser:0x061db3b0, CefFrame:0x061db358) FrameName="<!--framePath //<!--frame1-->-->" MainFrame? False
  HandleLoadEnd(CefBrowser:0x061db3b0, CefFrame:0x061db358) FrameName="<!--framePath //<!--frame1-->-->" MainFrame? False
  HandleLoadEnd(CefBrowser:0x061db358, CefFrame:0x00000000)
http://www.google.co.uk/csi?v=3&s=web&action=&e=27744,27867,27886,28062,28065&ei=Ju0ATYOiAs24hAfqrYjuBw&expi=27744,27867,27886,28062,28065&imc=3&imn=3&imp=0&rt=xjsls.147,prt.149,xjses.234,xjsee.339,xjs.345,ol.358,iml.149


As you can see waiting for a HandleLoadEnd with a null frame is not enough as this occurs twice. I therefore tried to implement a countdown/countup latch to sum the number of starts minus ends and signal when the count returns to zero, this doesn't seem to be reliable though due to race conditions.

What I'd really like to do is to be able to track the state of each frame, this brings me to the next problem, there is no way to compare CefBrowsers of CefFrames for equality and the pointers passing in by the framework change continually as seen above. This is also the reason that I can't wrap and expose the frame related portions of the API, I can't tell which frame is being referred to.

What is the difference between the calls with a null frame argument and the mainframe?

Is there something that can be exposed that would act as a more natural navigation-complete/page-ready event? Is there a way of comparing frames/browsers for equality that I've missed?

Thanks in advance and apologies for the rambling nature of this post,

Tom.
chillitom
Techie
 
Posts: 18
Joined: Sat Nov 20, 2010 11:50 am

Re: Determining page state/working with frames.

Postby magreenblatt » Thu Dec 09, 2010 11:56 am

What is the difference between the calls with a null frame argument and the mainframe? Is there something that can be exposed that would act as a more natural navigation-complete/page-ready event?

You will see a call to HandleLoadStart/End for each frame (including the main frame) and one call to HandleLoadStart/End with an empty |frame| pointer that reflects the overall request. Your code snippet appears to demonstrate that HandleLoadStart/End are working as expected.

Additional calls to HandleLoadStart/End may occur at any time if the page content initiates a new load request, perhaps via an iframe. When it's safe for the host to execute JavaScript on the page content really requires an understanding of both the JavaScript and the page content. For instance, if a page uses a timer to load content later on, and JavaScript to be executed by the host depends on that content, then the host must be notified when that content is available. This can be done using a JavaScript callback implemented via window binding, for instance.

If the page content is unknown then there can be no guarantee that JavaScript executed on that content by the host is ever safe. The improvements to ExecuteJavaScript described in issue 151 would likely be helpful to you in this situation as the host could then catch the error condition and act accordingly.

Is there a way of comparing frames/browsers for equality that I've missed?

The window handle returned via CefBrowser::GetWindowHandle uniquely identifies the browser window. Within a particular browser window and a particular load context, the frame name returned by CefFrame::GetName uniquely identifies the frame.

Regards,
Marshall
magreenblatt
Site Admin
 
Posts: 12382
Joined: Fri May 29, 2009 6:57 pm

Re: Determining page state/working with frames.

Postby chillitom » Tue Dec 14, 2010 6:24 am

Thanks Marshall,

I appreciate the point about JavaScript execution being page dependent, it's a good one, if a site is heavily dynamic there's not a lot you can do to determine whether it has loaded in a manner that the user would recognise as complete. What would be fantastic though would be a way of telling when the browser has completed all its regular resource loading and display, something akin to notifiying when the onload methods have completed for all frames and the javascript engine has returned to idle. The point at which someone measuring site load times might agree that the site had fully loaded, I'm not sure how best to define this technically.

The WatiN library has a feature where by you can issue and instruction to the browser and then wait for it to complete: http://watin.svn.sourceforge.net/viewvc/watin/trunk/src/Core/Native/InternetExplorer/IEWaitForComplete.cs?revision=1166&view=markup#l60. This is extremely useful as it allows for sequential instructions to be issued to the browser to automate browsing, navigation and website testing.

Could you comment on how this might be achieved with CEF and what (if any) changes might be required? Would a simple callback notifying that the js engine/thread had returned to idle be enough?

The only thing I am currently monitoring is the completion of frame loading using the HandleLoadStart/End methods. This works for simple pages but fails on most sites with frames/js due to frames being loaded out of order, e.g. child frames haven't started loading when their parent finishes.

Whether I get to hack on CefSharp as part of the day job really hinges on whether I can achieve the same behaviour as WatiN/WebDriver, obviously I'm very keen to find a solution as this work is a lot of fun.

w.r.t. issue 151 I intend to take a look at this issue if you haven't already. You'll remember I was having slow VS troubles working with cef.sln, I think this may be due to ReSharper, we'll be moving to VS2010 v. shortly at which point I'll be able to uninstall ReSharper from 2008 which hopefully will allow me to start hacking on libcef.

Many Thanks,

Tom.
chillitom
Techie
 
Posts: 18
Joined: Sat Nov 20, 2010 11:50 am

Re: Determining page state/working with frames.

Postby magreenblatt » Tue Dec 14, 2010 10:35 am

What would be fantastic though would be a way of telling when the browser has completed all its regular resource loading and display, something akin to notifiying when the onload methods have completed for all frames and the javascript engine has returned to idle.

The intent of HandleLoadEnd with an empty frame pointer is to notify when the page has finished loading. An iframe is effectively a separate page that has been embedded in the current page. It would be interesting to know if onload for the parent page is called only after all child iframes have completed loading. If this is the case then we could potentially expose that notification to satisfy your requirement.

You could also define overall page completion to mean that no new page load events have been generated within a certain period of time. This definition could be implemented by marking the time when HandleLoadEnd (with an empty frame pointer) was last called and, if no new HandleLoadStart calls (with an empty frame pointer) are generated within a particular timeout, consider page load to be complete as of that last marked time.

Could you comment on how this might be achieved with CEF and what (if any) changes might be required? Would a simple callback notifying that the js engine/thread had returned to idle be enough?

Any JS idle time notification would be a mechanism of V8. If such a mechanism exists it could potentially be exposed via CEF. However, I don't think it would be a reliable basis for judgement in this context.

we'll be moving to VS2010 v. shortly at which point I'll be able to uninstall ReSharper from 2008 which hopefully will allow me to start hacking on libcef.

I don't think anyone is building Chromium or CEF with VS2010 yet. Also, GYP, which is used to generate Chromium and CEF project files, does not yet support VS2010. http://code.google.com/p/gyp/issues/detail?id=96
magreenblatt
Site Admin
 
Posts: 12382
Joined: Fri May 29, 2009 6:57 pm

Re: Determining page state/working with frames.

Postby chillitom » Tue Dec 14, 2010 10:51 am

Thanks Marshall, I'll try coding up the inactivity period you suggest and see how that goes though I suspect something more concrete might be required.

Re. VS2010 I merely meant that when all my C# coding moves to 2010 I'll be able to uninstall ReSharper from 2008 and use that.. I suspect that it is ReSharper that is crippling VS despite the fact that it's disabled.

T.
chillitom
Techie
 
Posts: 18
Joined: Sat Nov 20, 2010 11:50 am

Re: Determining page state/working with frames.

Postby JulianGuppy » Wed Mar 13, 2013 7:59 am

This is something I am interested in resolving. I am using cefsharp in a .net environment and I am trying to determine that all the frames are loaded in a page (I am trying to get a pointer in the right direction) and/or how to use the OnLoadStart() and OnLoadEnd() in a .net environment... any help would be appreciated.

I am exercising and testing a site (not mine) that has a lot of frames in a frameset and I cant do certain things until I know that all frames have loaded

Whats the right way to do this

Regards julian
JulianGuppy
Newbie
 
Posts: 1
Joined: Wed Mar 13, 2013 7:51 am


Return to Support Forum

Who is online

Users browsing this forum: Google [Bot] and 42 guests