Skip to content

Commit fefe914

Browse files
committed
Page setviewport
1 parent 9f53082 commit fefe914

31 files changed

+420
-104
lines changed

lib/PuppeteerSharp.Nunit/TestExpectations/TestExpectations.local.json

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,97 @@
512512
},
513513
{
514514
"comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one",
515-
"testIdPattern": "[emulation.spec] *",
515+
"testIdPattern": "[emulation.spec] *Page.emulate *",
516+
"platforms": [
517+
"darwin",
518+
"linux",
519+
"win32"
520+
],
521+
"parameters": [
522+
"webDriverBiDi"
523+
],
524+
"expectations": [
525+
"FAIL"
526+
]
527+
},
528+
{
529+
"comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one",
530+
"testIdPattern": "[emulation.spec] *Page.emulateCPU*",
531+
"platforms": [
532+
"darwin",
533+
"linux",
534+
"win32"
535+
],
536+
"parameters": [
537+
"webDriverBiDi"
538+
],
539+
"expectations": [
540+
"FAIL"
541+
]
542+
},
543+
{
544+
"comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one",
545+
"testIdPattern": "[emulation.spec] *Page.emulateMediaFeatures*",
546+
"platforms": [
547+
"darwin",
548+
"linux",
549+
"win32"
550+
],
551+
"parameters": [
552+
"webDriverBiDi"
553+
],
554+
"expectations": [
555+
"FAIL"
556+
]
557+
},
558+
{
559+
"comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one",
560+
"testIdPattern": "[emulation.spec] *Page.emulateMediaType*",
561+
"platforms": [
562+
"darwin",
563+
"linux",
564+
"win32"
565+
],
566+
"parameters": [
567+
"webDriverBiDi"
568+
],
569+
"expectations": [
570+
"FAIL"
571+
]
572+
},
573+
{
574+
"comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one",
575+
"testIdPattern": "[emulation.spec] *Page.emulateNetworkConditions*",
576+
"platforms": [
577+
"darwin",
578+
"linux",
579+
"win32"
580+
],
581+
"parameters": [
582+
"webDriverBiDi"
583+
],
584+
"expectations": [
585+
"FAIL"
586+
]
587+
},
588+
{
589+
"comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one",
590+
"testIdPattern": "[emulation.spec] *Page.emulateTimezone*",
591+
"platforms": [
592+
"darwin",
593+
"linux",
594+
"win32"
595+
],
596+
"parameters": [
597+
"webDriverBiDi"
598+
],
599+
"expectations": [
600+
"FAIL"
601+
]
602+
},
603+
{
604+
"comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one",
605+
"testIdPattern": "[emulation.spec] *Page.emulateVision*",
516606
"platforms": [
517607
"darwin",
518608
"linux",

lib/PuppeteerSharp.Tests/DeviceRequestPromptTests/MockCDPSession.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ public Task<T> SendAsync<T>(string method, object args = null, CommandOptions op
5353
public TargetType TargetType { get; }
5454
public Task DetachAsync() => Task.CompletedTask;
5555

56+
public void Close(string closeReason)
57+
{
58+
59+
}
60+
5661
internal void OnMessage(ConnectionResponse obj)
5762
=> MessageReceived?.Invoke(this, new MessageEventArgs
5863
{

lib/PuppeteerSharp/Bidi/BidiBrowser.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ private BidiBrowser(Core.Browser browserCore, LaunchOptions options, ILoggerFact
4848
_options = options;
4949
BrowserCore = browserCore;
5050
_logger = loggerFactory.CreateLogger<BidiBrowser>();
51+
LoggerFactory = loggerFactory;
5152
}
5253

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

79+
internal ILoggerFactory LoggerFactory { get; set; }
80+
7881
internal BiDiDriver Driver => BrowserCore.Session.Driver;
7982

8083
internal Core.Browser BrowserCore { get; }

lib/PuppeteerSharp/Bidi/BidiCdpSession.cs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
namespace PuppeteerSharp.Bidi;
3232

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

5151
/// <inheritdoc />
52-
public ILoggerFactory LoggerFactory { get; }
52+
public ILoggerFactory LoggerFactory { get; } = loggerFactory;
5353

5454
/// <inheritdoc />
5555
public string Id { get; }
5656

5757
/// <inheritdoc />
58-
public string CloseReason { get; }
58+
public string CloseReason { get; private set; }
5959

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

62-
internal BidiFrame Frame { get; set; }
62+
internal BidiFrame Frame { get; set; } = bidiFrame;
6363

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

73+
/// <inheritdoc />
74+
public void Close(string reason = null)
75+
{
76+
CloseReason = reason;
77+
OnClose();
78+
}
79+
7380
internal void OnClose()
7481
{
7582
throw new NotImplementedException();

lib/PuppeteerSharp/Bidi/BidiFrame.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public class BidiFrame : Frame
3939

4040
internal BidiFrame(BidiPage parentPage, BidiFrame parentFrame, BrowsingContext browsingContext)
4141
{
42+
Client = new BidiCdpSession(this, parentPage.BidiBrowser.LoggerFactory);
4243
ParentPage = parentPage;
4344
ParentFrame = parentFrame;
4445
BrowsingContext = browsingContext;
@@ -60,7 +61,7 @@ internal BidiFrame(BidiPage parentPage, BidiFrame parentFrame, BrowsingContext b
6061
public override IPage Page => BidiPage;
6162

6263
/// <inheritdoc />
63-
public override CDPSession Client { get; protected set; }
64+
public override ICDPSession Client { get; protected set; }
6465

6566
/// <inheritdoc />
6667
internal override Realm MainRealm => _realms.Default;

lib/PuppeteerSharp/Bidi/BidiPage.cs

Lines changed: 113 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,27 @@
2323
using System;
2424
using System.Collections.Concurrent;
2525
using System.Collections.Generic;
26+
using System.Diagnostics;
2627
using System.Linq;
2728
using System.Threading.Tasks;
2829
using PuppeteerSharp.Bidi.Core;
2930
using PuppeteerSharp.Helpers;
3031
using PuppeteerSharp.Media;
32+
using WebDriverBiDi.BrowsingContext;
3133

3234
namespace PuppeteerSharp.Bidi;
3335

3436
/// <inheritdoc />
3537
public class BidiPage : Page
3638
{
39+
private readonly CdpEmulationManager _cdpEmulationManager;
40+
3741
internal BidiPage(BidiBrowserContext browserContext, BrowsingContext browsingContext) : base(browserContext.ScreenshotTaskQueue)
3842
{
3943
BrowserContext = browserContext;
44+
Browser = browserContext.Browser;
4045
BidiMainFrame = BidiFrame.From(this, null, browsingContext);
46+
_cdpEmulationManager = new CdpEmulationManager(BidiMainFrame.Client);
4147
}
4248

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

8187
/// <inheritdoc />
82-
public override Task BringToFrontAsync() => throw new NotImplementedException();
88+
public override async Task BringToFrontAsync()
89+
=> await BidiMainFrame.BrowsingContext.ActivateAsync().ConfigureAwait(false);
8390

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

141148
/// <inheritdoc />
142-
public override Task SetViewportAsync(ViewPortOptions viewport) => throw new NotImplementedException();
149+
public override async Task SetViewportAsync(ViewPortOptions viewport)
150+
{
151+
if (viewport == null)
152+
{
153+
throw new ArgumentNullException(nameof(viewport));
154+
}
155+
156+
if (!BidiBrowser.CdpSupported)
157+
{
158+
await BidiMainFrame.BrowsingContext.SetViewportAsync(
159+
new SetViewportOptions()
160+
{
161+
Viewport = viewport?.Width > 0 && viewport?.Height > 0
162+
? new WebDriverBiDi.BrowsingContext.Viewport()
163+
{
164+
Width = (ulong)viewport.Width,
165+
Height = (ulong)viewport.Height,
166+
}
167+
: null,
168+
DevicePixelRatio = viewport?.DeviceScaleFactor,
169+
}).ConfigureAwait(false);
170+
Viewport = viewport;
171+
return;
172+
}
173+
174+
var needsReload = await _cdpEmulationManager.EmulateViewportAsync(viewport).ConfigureAwait(false);
175+
Viewport = viewport;
176+
177+
if (needsReload)
178+
{
179+
await ReloadAsync().ConfigureAwait(false);
180+
}
181+
}
143182

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

209248
/// <inheritdoc />
210-
protected override Task<string> PerformScreenshotAsync(ScreenshotType type, ScreenshotOptions options) => throw new NotImplementedException();
249+
protected override async Task<string> PerformScreenshotAsync(ScreenshotType type, ScreenshotOptions options)
250+
{
251+
Debug.Assert(options != null, nameof(options) + " != null");
252+
253+
if (options.OmitBackground)
254+
{
255+
throw new PuppeteerException("BiDi does not support 'omitBackground'.");
256+
}
257+
258+
if (options.OptimizeForSpeed == true)
259+
{
260+
throw new PuppeteerException("BiDi does not support 'optimizeForSpeed'.");
261+
}
262+
263+
if (options.FromSurface == true)
264+
{
265+
throw new PuppeteerException("BiDi does not support 'fromSurface'.");
266+
}
267+
268+
if (options.Clip != null && options.Clip.Scale != 1)
269+
{
270+
throw new PuppeteerException("BiDi does not support 'scale' in 'clip'.");
271+
}
272+
273+
BoundingBox box;
274+
if (options.Clip != null)
275+
{
276+
if (options.CaptureBeyondViewport)
277+
{
278+
box = options.Clip;
279+
}
280+
else
281+
{
282+
// The clip is always with respect to the document coordinates, so we
283+
// need to convert this to viewport coordinates when we aren't capturing
284+
// beyond the viewport.
285+
var points = await EvaluateFunctionAsync<decimal[]>(@"() => {
286+
if (!window.visualViewport) {
287+
throw new Error('window.visualViewport is not supported.');
288+
}
289+
return [
290+
window.visualViewport.pageLeft,
291+
window.visualViewport.pageTop,
292+
];
293+
}").ConfigureAwait(false);
294+
295+
options.Clip.X += decimal.Floor(points[0]);
296+
options.Clip.Y += decimal.Floor(points[1]);
297+
}
298+
}
299+
300+
var fileType = options.Type switch
301+
{
302+
ScreenshotType.Jpeg => "jpg",
303+
ScreenshotType.Png => "png",
304+
ScreenshotType.Webp => "webp",
305+
_ => "png",
306+
};
307+
308+
// TODO: Missing box
309+
var data = await BidiMainFrame.BrowsingContext.CaptureScreenshotAsync(new ScreenshotParameters()
310+
{
311+
Origin = options.CaptureBeyondViewport ? ScreenshotOrigin.Document : ScreenshotOrigin.Viewport,
312+
Format = new ImageFormat()
313+
{
314+
Type = $"image/{fileType}",
315+
Quality = options.Quality / 100,
316+
},
317+
}).ConfigureAwait(false);
318+
319+
return data;
320+
}
211321

212322
/// <inheritdoc />
213323
protected override Task ExposeFunctionAsync(string name, Delegate puppeteerFunction) => throw new NotImplementedException();

lib/PuppeteerSharp/Bidi/BidiWebWorker.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public BidiWebWorker(string url) : base(url)
3030
{
3131
}
3232

33-
public override CDPSession Client { get; }
33+
public override ICDPSession Client { get; }
3434

3535
internal override IsolatedWorld World { get; }
3636

0 commit comments

Comments
 (0)