Lockdown is right. The PDF viewer in a browser container is safer than with software like Adobe Reader... Browsers are still exploited, someone recently exploited the V8 engine in Google Chrome, but on the whole it tends to be safer if we look at how samples in the wild operate and the common targets by traditional malware authors.
The traditional browsers like Microsoft Edge and Google Chrome (well, the Chromium engine sandbox actually - it comes with settings you can set when working with the Chromium engine and Google have an interface for this known as "flags" even though it isn't user-friendly) will have many policies enabled from restricting module loading depending on certificate signing to blocking Win32k system calls and forcing ASLR/DEP (if it wasn't already enabled for a peculiar reason). All in all, all of the policies being applied will make exploitation harder. Even if an attacker already had a valid vulnerability which they had figured out how to exploit, deployment could still be very tricky due to all of these policy features (not to mention that different people will have different ones enabled, making it less predictable regarding the success ratio).
For example, Address Space Layout Randomization (ASLR) will re-locate the images in memory per session. What people do not usually realize is that this does not actually apply to Windows modules such as NTDLL, WIN32U, KERNELBASE, KERNEL32, USER32, SECHOST, ADVAPI32, and others - the base address for those modules will be changed per system boot. For example, all WOW64 processes (which would mean the environment is x64) will have the same base address in their own virtual address space for KERNEL32.DLL, but this base address won't apply to a process with an image of another architecture (e.g. compiled for x64), yet those x64 processes will have the same base addresses in their virtual address space for Windows modules as well. However, if we had a module named "Opcode.dll" which was loaded by "Opcode.exe" and ASLR was being forced, the base address of "Opcode.dll" would shuffle each session for "Opcode.exe". This means that if an attacker were to be targeting exploitation of a feature within "Opcode.dll" loaded in the address space of "Opcode.exe" and needed the addresses to routines (either non-exported or exported), they wouldn't be able to rely on hard-coded addresses because the addresses would change per session for "Opcode.exe".
To explain what the base address is, it is where XXXX is loaded in memory. The base address of "Opcode.dll" could be 0xXXXX, but next session it could be + or - 0xXXXX from the location of the last session. When you re-locate the base image in-memory, you're basically moving the image elsewhere... And fixing references so no one who should be accessing the memory ends up trying to access the previous location. However in the case of features like ASLR being enabled from compilation, the Windows Loader handles it all so the base images aren't re-located too far down the road. When the base address moves, everything contained within that image in memory has its address changed as well. Why? Let's say we have a bowl of pasta... If we move that bowl, all of the pasta moves with it. The start is still the bowl and as we keep adding on 10 we find a new piece of pasta. However, if the bowl starts at 0x1000 and we have to +10 for each piece of pasta, it means pasta piece 3 will be 0x1000 + 0x30 which is 0x1030. Now if we were to re-locate the base (the bowl in this example) to 0x2000, the third piece of pasta will no longer be located at 0x1030, it'll be located at 0x2000 because the base is now 0x2000 and not 0x1000 and we still have to +0x30 which is the offset.
Another example would be Data Execution Prevention (DEP). It is used to prevent exploitation because an attacker will need to gain code execution one way or another, so if they were to just dump their shell-code somewhere... Nope, not going to work mate, you'll need executable rights where you currently are and you'll need to do it somehow. Now, if the exploit attack is external and the system is already compromised then that is quite simple (NtProtectVirtualMemory or allocate new memory) but in the case of an exploit coming from... hmm, the web-browser for example, it wouldn't be such a simple thing to avoid all of the time. Why? Because the browser would not be compromised on the local host properly until post-exploitation, and without that access, vulnerability XXXX may not be accomplish-able because of exploit mitigation features XXXX (e.g. ASLR, DEP, etc.).