Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bidi Page setviewport #2853

Merged
merged 3 commits into from
Dec 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 106 additions & 1 deletion lib/PuppeteerSharp.Nunit/TestExpectations/TestExpectations.local.json
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,21 @@
"FAIL"
]
},
{
"comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one",
"testIdPattern": "[navigation.spec] navigation Page.waitForNavigation*should work when subframe issues window.stop()",
"platforms": [
"darwin",
"linux",
"win32"
],
"parameters": [
"webDriverBiDi"
],
"expectations": [
"FAIL"
]
},
{
"comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one",
"testIdPattern": "[navigation.spec] *should navigate to dataURL and fire dataURL requests*",
Expand Down Expand Up @@ -512,7 +527,97 @@
},
{
"comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one",
"testIdPattern": "[emulation.spec] *",
"testIdPattern": "[emulation.spec] *Page.emulate *",
"platforms": [
"darwin",
"linux",
"win32"
],
"parameters": [
"webDriverBiDi"
],
"expectations": [
"FAIL"
]
},
{
"comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one",
"testIdPattern": "[emulation.spec] *Page.emulateCPU*",
"platforms": [
"darwin",
"linux",
"win32"
],
"parameters": [
"webDriverBiDi"
],
"expectations": [
"FAIL"
]
},
{
"comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one",
"testIdPattern": "[emulation.spec] *Page.emulateMediaFeatures*",
"platforms": [
"darwin",
"linux",
"win32"
],
"parameters": [
"webDriverBiDi"
],
"expectations": [
"FAIL"
]
},
{
"comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one",
"testIdPattern": "[emulation.spec] *Page.emulateMediaType*",
"platforms": [
"darwin",
"linux",
"win32"
],
"parameters": [
"webDriverBiDi"
],
"expectations": [
"FAIL"
]
},
{
"comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one",
"testIdPattern": "[emulation.spec] *Page.emulateNetworkConditions*",
"platforms": [
"darwin",
"linux",
"win32"
],
"parameters": [
"webDriverBiDi"
],
"expectations": [
"FAIL"
]
},
{
"comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one",
"testIdPattern": "[emulation.spec] *Page.emulateTimezone*",
"platforms": [
"darwin",
"linux",
"win32"
],
"parameters": [
"webDriverBiDi"
],
"expectations": [
"FAIL"
]
},
{
"comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one",
"testIdPattern": "[emulation.spec] *Page.emulateVision*",
"platforms": [
"darwin",
"linux",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ public Task<T> SendAsync<T>(string method, object args = null, CommandOptions op
public TargetType TargetType { get; }
public Task DetachAsync() => Task.CompletedTask;

public void Close(string closeReason)
{

}

internal void OnMessage(ConnectionResponse obj)
=> MessageReceived?.Invoke(this, new MessageEventArgs
{
Expand Down
3 changes: 3 additions & 0 deletions lib/PuppeteerSharp/Bidi/BidiBrowser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ private BidiBrowser(Core.Browser browserCore, LaunchOptions options, ILoggerFact
_options = options;
BrowserCore = browserCore;
_logger = loggerFactory.CreateLogger<BidiBrowser>();
LoggerFactory = loggerFactory;
}

/// <inheritdoc />
Expand Down Expand Up @@ -75,6 +76,8 @@ private BidiBrowser(Core.Browser browserCore, LaunchOptions options, ILoggerFact
"cdp.Page.screencastFrame",
];

internal ILoggerFactory LoggerFactory { get; set; }

internal BiDiDriver Driver => BrowserCore.Session.Driver;

internal Core.Browser BrowserCore { get; }
Expand Down
15 changes: 11 additions & 4 deletions lib/PuppeteerSharp/Bidi/BidiCdpSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
namespace PuppeteerSharp.Bidi;

/// <inheritdoc />
public class BidiCdpSession : ICDPSession
public class BidiCdpSession(BidiFrame bidiFrame, ILoggerFactory loggerFactory) : ICDPSession
{
// I don't like the idea of having this static field. But this is the original implementation.
private static readonly ConcurrentDictionary<string, BidiCdpSession> _sessions = new();
Expand All @@ -49,17 +49,17 @@ public class BidiCdpSession : ICDPSession
public event EventHandler<SessionEventArgs> SessionDetached;

/// <inheritdoc />
public ILoggerFactory LoggerFactory { get; }
public ILoggerFactory LoggerFactory { get; } = loggerFactory;

/// <inheritdoc />
public string Id { get; }

/// <inheritdoc />
public string CloseReason { get; }
public string CloseReason { get; private set; }

internal static IEnumerable<BidiCdpSession> Sessions => _sessions.Values;

internal BidiFrame Frame { get; set; }
internal BidiFrame Frame { get; set; } = bidiFrame;

/// <inheritdoc />
public Task<T> SendAsync<T>(string method, object args = null, CommandOptions options = null) => throw new NotImplementedException();
Expand All @@ -70,6 +70,13 @@ public class BidiCdpSession : ICDPSession
/// <inheritdoc />
public Task DetachAsync() => throw new NotImplementedException();

/// <inheritdoc />
public void Close(string reason = null)
{
CloseReason = reason;
OnClose();
}

internal void OnClose()
{
throw new NotImplementedException();
Expand Down
3 changes: 2 additions & 1 deletion lib/PuppeteerSharp/Bidi/BidiFrame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public class BidiFrame : Frame

internal BidiFrame(BidiPage parentPage, BidiFrame parentFrame, BrowsingContext browsingContext)
{
Client = new BidiCdpSession(this, parentPage.BidiBrowser.LoggerFactory);
ParentPage = parentPage;
ParentFrame = parentFrame;
BrowsingContext = browsingContext;
Expand All @@ -60,7 +61,7 @@ internal BidiFrame(BidiPage parentPage, BidiFrame parentFrame, BrowsingContext b
public override IPage Page => BidiPage;

/// <inheritdoc />
public override CDPSession Client { get; protected set; }
public override ICDPSession Client { get; protected set; }

/// <inheritdoc />
internal override Realm MainRealm => _realms.Default;
Expand Down
116 changes: 113 additions & 3 deletions lib/PuppeteerSharp/Bidi/BidiPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,27 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using PuppeteerSharp.Bidi.Core;
using PuppeteerSharp.Helpers;
using PuppeteerSharp.Media;
using WebDriverBiDi.BrowsingContext;

namespace PuppeteerSharp.Bidi;

/// <inheritdoc />
public class BidiPage : Page
{
private readonly CdpEmulationManager _cdpEmulationManager;

internal BidiPage(BidiBrowserContext browserContext, BrowsingContext browsingContext) : base(browserContext.ScreenshotTaskQueue)
{
BrowserContext = browserContext;
Browser = browserContext.Browser;
BidiMainFrame = BidiFrame.From(this, null, browsingContext);
_cdpEmulationManager = new CdpEmulationManager(BidiMainFrame.Client);
}

/// <inheritdoc />
Expand Down Expand Up @@ -79,7 +85,8 @@ internal BidiPage(BidiBrowserContext browserContext, BrowsingContext browsingCon
public override Task AuthenticateAsync(Credentials credentials) => throw new NotImplementedException();

/// <inheritdoc />
public override Task BringToFrontAsync() => throw new NotImplementedException();
public override async Task BringToFrontAsync()
=> await BidiMainFrame.BrowsingContext.ActivateAsync().ConfigureAwait(false);

/// <inheritdoc />
public override Task EmulateVisionDeficiencyAsync(VisionDeficiency type) => throw new NotImplementedException();
Expand Down Expand Up @@ -139,7 +146,39 @@ internal BidiPage(BidiBrowserContext browserContext, BrowsingContext browsingCon
public override Task SetUserAgentAsync(string userAgent, UserAgentMetadata userAgentData = null) => throw new NotImplementedException();

/// <inheritdoc />
public override Task SetViewportAsync(ViewPortOptions viewport) => throw new NotImplementedException();
public override async Task SetViewportAsync(ViewPortOptions viewport)
{
if (viewport == null)
{
throw new ArgumentNullException(nameof(viewport));
}

if (!BidiBrowser.CdpSupported)
{
await BidiMainFrame.BrowsingContext.SetViewportAsync(
new SetViewportOptions()
{
Viewport = viewport?.Width > 0 && viewport?.Height > 0
? new WebDriverBiDi.BrowsingContext.Viewport()
{
Width = (ulong)viewport.Width,
Height = (ulong)viewport.Height,
}
: null,
DevicePixelRatio = viewport?.DeviceScaleFactor,
}).ConfigureAwait(false);
Viewport = viewport;
return;
}

var needsReload = await _cdpEmulationManager.EmulateViewportAsync(viewport).ConfigureAwait(false);
Viewport = viewport;

if (needsReload)
{
await ReloadAsync().ConfigureAwait(false);
}
}

/// <inheritdoc />
public override Task SetCookieAsync(params CookieParam[] cookies) => throw new NotImplementedException();
Expand Down Expand Up @@ -207,7 +246,78 @@ internal static BidiPage From(BidiBrowserContext browserContext, BrowsingContext
protected override Task<byte[]> PdfInternalAsync(string file, PdfOptions options) => throw new NotImplementedException();

/// <inheritdoc />
protected override Task<string> PerformScreenshotAsync(ScreenshotType type, ScreenshotOptions options) => throw new NotImplementedException();
protected override async Task<string> PerformScreenshotAsync(ScreenshotType type, ScreenshotOptions options)
{
Debug.Assert(options != null, nameof(options) + " != null");

if (options.OmitBackground)
{
throw new PuppeteerException("BiDi does not support 'omitBackground'.");
}

if (options.OptimizeForSpeed == true)
{
throw new PuppeteerException("BiDi does not support 'optimizeForSpeed'.");
}

if (options.FromSurface == true)
{
throw new PuppeteerException("BiDi does not support 'fromSurface'.");
}

if (options.Clip != null && options.Clip.Scale != 1)
{
throw new PuppeteerException("BiDi does not support 'scale' in 'clip'.");
}

BoundingBox box;
if (options.Clip != null)
{
if (options.CaptureBeyondViewport)
{
box = options.Clip;
}
else
{
// The clip is always with respect to the document coordinates, so we
// need to convert this to viewport coordinates when we aren't capturing
// beyond the viewport.
var points = await EvaluateFunctionAsync<decimal[]>(@"() => {
if (!window.visualViewport) {
throw new Error('window.visualViewport is not supported.');
}
return [
window.visualViewport.pageLeft,
window.visualViewport.pageTop,
];
}").ConfigureAwait(false);

options.Clip.X += decimal.Floor(points[0]);
options.Clip.Y += decimal.Floor(points[1]);
}
}

var fileType = options.Type switch
{
ScreenshotType.Jpeg => "jpg",
ScreenshotType.Png => "png",
ScreenshotType.Webp => "webp",
_ => "png",
};

// TODO: Missing box
var data = await BidiMainFrame.BrowsingContext.CaptureScreenshotAsync(new ScreenshotParameters()
{
Origin = options.CaptureBeyondViewport ? ScreenshotOrigin.Document : ScreenshotOrigin.Viewport,
Format = new ImageFormat()
{
Type = $"image/{fileType}",
Quality = options.Quality / 100,
},
}).ConfigureAwait(false);

return data;
}

/// <inheritdoc />
protected override Task ExposeFunctionAsync(string name, Delegate puppeteerFunction) => throw new NotImplementedException();
Expand Down
2 changes: 1 addition & 1 deletion lib/PuppeteerSharp/Bidi/BidiWebWorker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public BidiWebWorker(string url) : base(url)
{
}

public override CDPSession Client { get; }
public override ICDPSession Client { get; }

internal override IsolatedWorld World { get; }

Expand Down
Loading
Loading