2020-03-10 21:51:26 +01:00
|
|
|
// Copyright (c) Microsoft Corporation.
|
|
|
|
// Licensed under the MIT license.
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#ifdef UNIT_TESTING
|
|
|
|
class SizeTests;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
|
|
|
{
|
|
|
|
class size
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
constexpr size() noexcept :
|
|
|
|
size(0, 0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
// On 64-bit processors, int and ptrdiff_t are different fundamental types.
|
|
|
|
// On 32-bit processors, they're the same which makes this a double-definition
|
|
|
|
// with the `ptrdiff_t` one below.
|
|
|
|
#if defined(_M_AMD64) || defined(_M_ARM64)
|
|
|
|
constexpr size(int width, int height) noexcept :
|
|
|
|
size(static_cast<ptrdiff_t>(width), static_cast<ptrdiff_t>(height))
|
|
|
|
{
|
|
|
|
}
|
Adjusts High DPI scaling to enable differential rendering (#5345)
## Summary of the Pull Request
- Adjusts scaling practices in `DxEngine` (and related scaling practices in `TerminalControl`) for pixel-perfect row baselines and spacing at High DPI such that differential row-by-row rendering can be applied at High DPI.
## References
- #5185
## PR Checklist
* [x] Closes #5320, closes #3515, closes #1064
* [x] I work here.
* [x] Manually tested.
* [x] No doc.
* [x] Am core contributor. Also discussed with some of them already via Teams.
## Detailed Description of the Pull Request / Additional comments
**WAS:**
- We were using implicit DPI scaling on the `ID2D1RenderTarget` and running all of our processing in DIPs (Device-Independent Pixels). That's all well and good for getting things bootstrapped quickly, but it leaves the actual scaling of the draw commands up to the discretion of the rendering target.
- When we don't get to explicitly choose exactly how many pixels tall/wide and our X/Y placement perfectly, the nature of floating point multiplication and division required to do the presentation can cause us to drift off slightly out of our control depending on what the final display resolution actually is.
- Differential drawing cannot work unless we can know the exact integer pixels that need to be copied/moved/preserved/replaced between frames to give to the `IDXGISwapChain1::Present1` method. If things spill into fractional pixels or the sizes of rows/columns vary as they are rounded up and down implicitly, then we cannot do the differential rendering.
**NOW:**
- When deciding on a font, the `DxEngine` will take the scale factor into account and adjust the proposed height of the requested font. Then the remainder of the existing code that adjusts the baseline and integer-ifies each character cell will run naturally from there. That code already works correctly to align the height at normal DPI and scale out the font heights and advances to take an exact integer of pixels.
- `TermControl` has to use the scale now, in some places, and stop scaling in other places. This has to do with how the target's nature used to be implicit and is now explicit. For instance, determining where the cursor click hits must be scaled now. And determining the pixel size of the display canvas must no longer be scaled.
- `DxEngine` will no longer attempt to scale the invalid regions per my attempts in #5185 because the cell size is scaled. So it should work the same as at 96 DPI.
- The block is removed from the `DxEngine` that was causing a full invalidate on every frame at High DPI.
- A TODO was removed from `TermControl` that was invalidating everything when the DPI changed because the underlying renderer will already do that.
## Validation Steps Performed
* [x] Check at 150% DPI. Print text, scroll text down and up, do selection.
* [x] Check at 100% DPI. Print text, scroll text down and up, do selection.
* [x] Span two different DPI monitors and drag between them.
* [x] Giant pile of tests in https://github.com/microsoft/terminal/pull/5345#issuecomment-614127648
Co-authored-by: Dustin Howett <duhowett@microsoft.com>
Co-authored-by: Mike Griese <migrie@microsoft.com>
2020-04-22 23:59:51 +02:00
|
|
|
constexpr size(ptrdiff_t width, int height) noexcept :
|
|
|
|
size(width, static_cast<ptrdiff_t>(height))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
constexpr size(int width, ptrdiff_t height) noexcept :
|
|
|
|
size(static_cast<ptrdiff_t>(width), height)
|
|
|
|
{
|
|
|
|
}
|
2020-03-10 21:51:26 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
size(size_t width, size_t height)
|
|
|
|
{
|
2021-04-26 21:36:23 +02:00
|
|
|
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(width).AssignIfValid(&_width));
|
|
|
|
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(height).AssignIfValid(&_height));
|
|
|
|
}
|
|
|
|
size(long width, long height)
|
|
|
|
{
|
2020-03-10 21:51:26 +01:00
|
|
|
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(width).AssignIfValid(&_width));
|
|
|
|
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(height).AssignIfValid(&_height));
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr size(ptrdiff_t width, ptrdiff_t height) noexcept :
|
|
|
|
_width(width),
|
|
|
|
_height(height)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
til::rectangle (#4912)
## Summary of the Pull Request
Introduces convenience type `til::rectangle` which automatically implements our best practices for rectangle-related types and provides automatic conversions in/out of the relevant types.
## PR Checklist
* [x] In support of Differential Rendering #778
* [X] I work here.
* [x] Tests added/passed
* [x] I'm a core contributor.
## Detailed Description of the Pull Request / Additional comments
- Automatically converts in from anything with a Left/Top/Right/Bottom or left/top/right/bottom (Win32 `RECT`)
- Automatically converts Console type `SMALL_RECT` and shifts it from **inclusive** to **exclusive** on instantiation
- Automatically converts out to `SMALL_RECT` (converting back to **inclusive**), `RECT`, or `D2D1_RECT_F`.
- Constructs from bare integers written into source file
- Constructs from a single `til::point` as a 1x1 size rectangle with top-left corner (origin) at that point
- Constructs from a single `til::size` as a WxH size rectangle with top-left corner (origin) at 0,0
- Constructs from a `til::point` and a `til::size` representing the top-left corner and the width by height.
- Constructs from a `til::point` and another `til::point` representing the top-left corner and the **exclusive** bottom-right corner.
- Default constructs to empty
- Uses Chromium numerics for all basic math operations (+, -, *, /)
- Provides equality tests
- Provides `operator bool` to know when it's valid (has an area > 0) and `empty()` to know the contrary
- Accessors for left/top/right/bottom
- Type converting accessors (that use safe conversions and throw) for left/top/right/bottom
- Convenience methods for finding width/height (with Chromium numerics operations) and type-converting templates (with Chromium numerics conversions).
- Accessors for origin (top-left point) and the size/dimensions (as a `til::size`).
- Intersect operation on `operator &` to find where two `til::rectangle`s overlap, returned as a `til::rectangle`.
- Union operation on `operator |` to find the total area covered by two `til::rectangles`, returned as a `til::rectangle`.
- Subtract operation on `operator -` to find the area remaining after one `til::rectangle` is removed from another, returned as a `til::some<til::rectangle, 4>`.
- TAEF/WEX Output and Comparators so they will print very nicely with `VERIFY` and `Log` macros in our testing suite.
- Additional comparators, TAEF/WEX output, and tests written on `til::some` to support the Subtract operation.
- A natvis
## Validation Steps Performed
- See automated tests of functionality.
2020-03-14 18:27:47 +01:00
|
|
|
// This template will convert to size from anything that has an X and a Y field that appear convertible to an integer value
|
2020-03-10 21:51:26 +01:00
|
|
|
template<typename TOther>
|
|
|
|
constexpr size(const TOther& other, std::enable_if_t<std::is_integral_v<decltype(std::declval<TOther>().X)> && std::is_integral_v<decltype(std::declval<TOther>().Y)>, int> /*sentinel*/ = 0) :
|
|
|
|
size(static_cast<ptrdiff_t>(other.X), static_cast<ptrdiff_t>(other.Y))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
til::rectangle (#4912)
## Summary of the Pull Request
Introduces convenience type `til::rectangle` which automatically implements our best practices for rectangle-related types and provides automatic conversions in/out of the relevant types.
## PR Checklist
* [x] In support of Differential Rendering #778
* [X] I work here.
* [x] Tests added/passed
* [x] I'm a core contributor.
## Detailed Description of the Pull Request / Additional comments
- Automatically converts in from anything with a Left/Top/Right/Bottom or left/top/right/bottom (Win32 `RECT`)
- Automatically converts Console type `SMALL_RECT` and shifts it from **inclusive** to **exclusive** on instantiation
- Automatically converts out to `SMALL_RECT` (converting back to **inclusive**), `RECT`, or `D2D1_RECT_F`.
- Constructs from bare integers written into source file
- Constructs from a single `til::point` as a 1x1 size rectangle with top-left corner (origin) at that point
- Constructs from a single `til::size` as a WxH size rectangle with top-left corner (origin) at 0,0
- Constructs from a `til::point` and a `til::size` representing the top-left corner and the width by height.
- Constructs from a `til::point` and another `til::point` representing the top-left corner and the **exclusive** bottom-right corner.
- Default constructs to empty
- Uses Chromium numerics for all basic math operations (+, -, *, /)
- Provides equality tests
- Provides `operator bool` to know when it's valid (has an area > 0) and `empty()` to know the contrary
- Accessors for left/top/right/bottom
- Type converting accessors (that use safe conversions and throw) for left/top/right/bottom
- Convenience methods for finding width/height (with Chromium numerics operations) and type-converting templates (with Chromium numerics conversions).
- Accessors for origin (top-left point) and the size/dimensions (as a `til::size`).
- Intersect operation on `operator &` to find where two `til::rectangle`s overlap, returned as a `til::rectangle`.
- Union operation on `operator |` to find the total area covered by two `til::rectangles`, returned as a `til::rectangle`.
- Subtract operation on `operator -` to find the area remaining after one `til::rectangle` is removed from another, returned as a `til::some<til::rectangle, 4>`.
- TAEF/WEX Output and Comparators so they will print very nicely with `VERIFY` and `Log` macros in our testing suite.
- Additional comparators, TAEF/WEX output, and tests written on `til::some` to support the Subtract operation.
- A natvis
## Validation Steps Performed
- See automated tests of functionality.
2020-03-14 18:27:47 +01:00
|
|
|
// This template will convert to size from anything that has a cx and a cy field that appear convertible to an integer value
|
2020-03-10 21:51:26 +01:00
|
|
|
template<typename TOther>
|
|
|
|
constexpr size(const TOther& other, std::enable_if_t<std::is_integral_v<decltype(std::declval<TOther>().cx)> && std::is_integral_v<decltype(std::declval<TOther>().cy)>, int> /*sentinel*/ = 0) :
|
|
|
|
size(static_cast<ptrdiff_t>(other.cx), static_cast<ptrdiff_t>(other.cy))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-03-27 23:48:49 +01:00
|
|
|
// This template will convert to size from anything that has a X and a Y field that are floating-point;
|
Adjusts High DPI scaling to enable differential rendering (#5345)
## Summary of the Pull Request
- Adjusts scaling practices in `DxEngine` (and related scaling practices in `TerminalControl`) for pixel-perfect row baselines and spacing at High DPI such that differential row-by-row rendering can be applied at High DPI.
## References
- #5185
## PR Checklist
* [x] Closes #5320, closes #3515, closes #1064
* [x] I work here.
* [x] Manually tested.
* [x] No doc.
* [x] Am core contributor. Also discussed with some of them already via Teams.
## Detailed Description of the Pull Request / Additional comments
**WAS:**
- We were using implicit DPI scaling on the `ID2D1RenderTarget` and running all of our processing in DIPs (Device-Independent Pixels). That's all well and good for getting things bootstrapped quickly, but it leaves the actual scaling of the draw commands up to the discretion of the rendering target.
- When we don't get to explicitly choose exactly how many pixels tall/wide and our X/Y placement perfectly, the nature of floating point multiplication and division required to do the presentation can cause us to drift off slightly out of our control depending on what the final display resolution actually is.
- Differential drawing cannot work unless we can know the exact integer pixels that need to be copied/moved/preserved/replaced between frames to give to the `IDXGISwapChain1::Present1` method. If things spill into fractional pixels or the sizes of rows/columns vary as they are rounded up and down implicitly, then we cannot do the differential rendering.
**NOW:**
- When deciding on a font, the `DxEngine` will take the scale factor into account and adjust the proposed height of the requested font. Then the remainder of the existing code that adjusts the baseline and integer-ifies each character cell will run naturally from there. That code already works correctly to align the height at normal DPI and scale out the font heights and advances to take an exact integer of pixels.
- `TermControl` has to use the scale now, in some places, and stop scaling in other places. This has to do with how the target's nature used to be implicit and is now explicit. For instance, determining where the cursor click hits must be scaled now. And determining the pixel size of the display canvas must no longer be scaled.
- `DxEngine` will no longer attempt to scale the invalid regions per my attempts in #5185 because the cell size is scaled. So it should work the same as at 96 DPI.
- The block is removed from the `DxEngine` that was causing a full invalidate on every frame at High DPI.
- A TODO was removed from `TermControl` that was invalidating everything when the DPI changed because the underlying renderer will already do that.
## Validation Steps Performed
* [x] Check at 150% DPI. Print text, scroll text down and up, do selection.
* [x] Check at 100% DPI. Print text, scroll text down and up, do selection.
* [x] Span two different DPI monitors and drag between them.
* [x] Giant pile of tests in https://github.com/microsoft/terminal/pull/5345#issuecomment-614127648
Co-authored-by: Dustin Howett <duhowett@microsoft.com>
Co-authored-by: Mike Griese <migrie@microsoft.com>
2020-04-22 23:59:51 +02:00
|
|
|
// a math type is required. If you _don't_ provide one, you're going to
|
|
|
|
// get a compile-time error about "cannot convert from initializer-list to til::size"
|
2020-03-27 23:48:49 +01:00
|
|
|
template<typename TilMath, typename TOther>
|
|
|
|
constexpr size(TilMath, const TOther& other, std::enable_if_t<std::is_floating_point_v<decltype(std::declval<TOther>().X)> && std::is_floating_point_v<decltype(std::declval<TOther>().Y)>, int> /*sentinel*/ = 0) :
|
|
|
|
size(TilMath::template cast<ptrdiff_t>(other.X), TilMath::template cast<ptrdiff_t>(other.Y))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
// This template will convert to size from anything that has a cx and a cy field that are floating-point;
|
Adjusts High DPI scaling to enable differential rendering (#5345)
## Summary of the Pull Request
- Adjusts scaling practices in `DxEngine` (and related scaling practices in `TerminalControl`) for pixel-perfect row baselines and spacing at High DPI such that differential row-by-row rendering can be applied at High DPI.
## References
- #5185
## PR Checklist
* [x] Closes #5320, closes #3515, closes #1064
* [x] I work here.
* [x] Manually tested.
* [x] No doc.
* [x] Am core contributor. Also discussed with some of them already via Teams.
## Detailed Description of the Pull Request / Additional comments
**WAS:**
- We were using implicit DPI scaling on the `ID2D1RenderTarget` and running all of our processing in DIPs (Device-Independent Pixels). That's all well and good for getting things bootstrapped quickly, but it leaves the actual scaling of the draw commands up to the discretion of the rendering target.
- When we don't get to explicitly choose exactly how many pixels tall/wide and our X/Y placement perfectly, the nature of floating point multiplication and division required to do the presentation can cause us to drift off slightly out of our control depending on what the final display resolution actually is.
- Differential drawing cannot work unless we can know the exact integer pixels that need to be copied/moved/preserved/replaced between frames to give to the `IDXGISwapChain1::Present1` method. If things spill into fractional pixels or the sizes of rows/columns vary as they are rounded up and down implicitly, then we cannot do the differential rendering.
**NOW:**
- When deciding on a font, the `DxEngine` will take the scale factor into account and adjust the proposed height of the requested font. Then the remainder of the existing code that adjusts the baseline and integer-ifies each character cell will run naturally from there. That code already works correctly to align the height at normal DPI and scale out the font heights and advances to take an exact integer of pixels.
- `TermControl` has to use the scale now, in some places, and stop scaling in other places. This has to do with how the target's nature used to be implicit and is now explicit. For instance, determining where the cursor click hits must be scaled now. And determining the pixel size of the display canvas must no longer be scaled.
- `DxEngine` will no longer attempt to scale the invalid regions per my attempts in #5185 because the cell size is scaled. So it should work the same as at 96 DPI.
- The block is removed from the `DxEngine` that was causing a full invalidate on every frame at High DPI.
- A TODO was removed from `TermControl` that was invalidating everything when the DPI changed because the underlying renderer will already do that.
## Validation Steps Performed
* [x] Check at 150% DPI. Print text, scroll text down and up, do selection.
* [x] Check at 100% DPI. Print text, scroll text down and up, do selection.
* [x] Span two different DPI monitors and drag between them.
* [x] Giant pile of tests in https://github.com/microsoft/terminal/pull/5345#issuecomment-614127648
Co-authored-by: Dustin Howett <duhowett@microsoft.com>
Co-authored-by: Mike Griese <migrie@microsoft.com>
2020-04-22 23:59:51 +02:00
|
|
|
// a math type is required. If you _don't_ provide one, you're going to
|
|
|
|
// get a compile-time error about "cannot convert from initializer-list to til::size"
|
2020-03-27 23:48:49 +01:00
|
|
|
template<typename TilMath, typename TOther>
|
|
|
|
constexpr size(TilMath, const TOther& other, std::enable_if_t<std::is_floating_point_v<decltype(std::declval<TOther>().cx)> && std::is_floating_point_v<decltype(std::declval<TOther>().cy)>, int> /*sentinel*/ = 0) :
|
|
|
|
size(TilMath::template cast<ptrdiff_t>(other.cx), TilMath::template cast<ptrdiff_t>(other.cy))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
// This template will convert to size from anything that has a Width and a Height field that are floating-point;
|
Adjusts High DPI scaling to enable differential rendering (#5345)
## Summary of the Pull Request
- Adjusts scaling practices in `DxEngine` (and related scaling practices in `TerminalControl`) for pixel-perfect row baselines and spacing at High DPI such that differential row-by-row rendering can be applied at High DPI.
## References
- #5185
## PR Checklist
* [x] Closes #5320, closes #3515, closes #1064
* [x] I work here.
* [x] Manually tested.
* [x] No doc.
* [x] Am core contributor. Also discussed with some of them already via Teams.
## Detailed Description of the Pull Request / Additional comments
**WAS:**
- We were using implicit DPI scaling on the `ID2D1RenderTarget` and running all of our processing in DIPs (Device-Independent Pixels). That's all well and good for getting things bootstrapped quickly, but it leaves the actual scaling of the draw commands up to the discretion of the rendering target.
- When we don't get to explicitly choose exactly how many pixels tall/wide and our X/Y placement perfectly, the nature of floating point multiplication and division required to do the presentation can cause us to drift off slightly out of our control depending on what the final display resolution actually is.
- Differential drawing cannot work unless we can know the exact integer pixels that need to be copied/moved/preserved/replaced between frames to give to the `IDXGISwapChain1::Present1` method. If things spill into fractional pixels or the sizes of rows/columns vary as they are rounded up and down implicitly, then we cannot do the differential rendering.
**NOW:**
- When deciding on a font, the `DxEngine` will take the scale factor into account and adjust the proposed height of the requested font. Then the remainder of the existing code that adjusts the baseline and integer-ifies each character cell will run naturally from there. That code already works correctly to align the height at normal DPI and scale out the font heights and advances to take an exact integer of pixels.
- `TermControl` has to use the scale now, in some places, and stop scaling in other places. This has to do with how the target's nature used to be implicit and is now explicit. For instance, determining where the cursor click hits must be scaled now. And determining the pixel size of the display canvas must no longer be scaled.
- `DxEngine` will no longer attempt to scale the invalid regions per my attempts in #5185 because the cell size is scaled. So it should work the same as at 96 DPI.
- The block is removed from the `DxEngine` that was causing a full invalidate on every frame at High DPI.
- A TODO was removed from `TermControl` that was invalidating everything when the DPI changed because the underlying renderer will already do that.
## Validation Steps Performed
* [x] Check at 150% DPI. Print text, scroll text down and up, do selection.
* [x] Check at 100% DPI. Print text, scroll text down and up, do selection.
* [x] Span two different DPI monitors and drag between them.
* [x] Giant pile of tests in https://github.com/microsoft/terminal/pull/5345#issuecomment-614127648
Co-authored-by: Dustin Howett <duhowett@microsoft.com>
Co-authored-by: Mike Griese <migrie@microsoft.com>
2020-04-22 23:59:51 +02:00
|
|
|
// a math type is required. If you _don't_ provide one, you're going to
|
|
|
|
// get a compile-time error about "cannot convert from initializer-list to til::size"
|
2020-03-27 23:48:49 +01:00
|
|
|
template<typename TilMath, typename TOther>
|
|
|
|
constexpr size(TilMath, const TOther& other, std::enable_if_t<std::is_floating_point_v<decltype(std::declval<TOther>().Width)> && std::is_floating_point_v<decltype(std::declval<TOther>().Height)>, int> /*sentinel*/ = 0) :
|
|
|
|
size(TilMath::template cast<ptrdiff_t>(other.Width), TilMath::template cast<ptrdiff_t>(other.Height))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
Adjusts High DPI scaling to enable differential rendering (#5345)
## Summary of the Pull Request
- Adjusts scaling practices in `DxEngine` (and related scaling practices in `TerminalControl`) for pixel-perfect row baselines and spacing at High DPI such that differential row-by-row rendering can be applied at High DPI.
## References
- #5185
## PR Checklist
* [x] Closes #5320, closes #3515, closes #1064
* [x] I work here.
* [x] Manually tested.
* [x] No doc.
* [x] Am core contributor. Also discussed with some of them already via Teams.
## Detailed Description of the Pull Request / Additional comments
**WAS:**
- We were using implicit DPI scaling on the `ID2D1RenderTarget` and running all of our processing in DIPs (Device-Independent Pixels). That's all well and good for getting things bootstrapped quickly, but it leaves the actual scaling of the draw commands up to the discretion of the rendering target.
- When we don't get to explicitly choose exactly how many pixels tall/wide and our X/Y placement perfectly, the nature of floating point multiplication and division required to do the presentation can cause us to drift off slightly out of our control depending on what the final display resolution actually is.
- Differential drawing cannot work unless we can know the exact integer pixels that need to be copied/moved/preserved/replaced between frames to give to the `IDXGISwapChain1::Present1` method. If things spill into fractional pixels or the sizes of rows/columns vary as they are rounded up and down implicitly, then we cannot do the differential rendering.
**NOW:**
- When deciding on a font, the `DxEngine` will take the scale factor into account and adjust the proposed height of the requested font. Then the remainder of the existing code that adjusts the baseline and integer-ifies each character cell will run naturally from there. That code already works correctly to align the height at normal DPI and scale out the font heights and advances to take an exact integer of pixels.
- `TermControl` has to use the scale now, in some places, and stop scaling in other places. This has to do with how the target's nature used to be implicit and is now explicit. For instance, determining where the cursor click hits must be scaled now. And determining the pixel size of the display canvas must no longer be scaled.
- `DxEngine` will no longer attempt to scale the invalid regions per my attempts in #5185 because the cell size is scaled. So it should work the same as at 96 DPI.
- The block is removed from the `DxEngine` that was causing a full invalidate on every frame at High DPI.
- A TODO was removed from `TermControl` that was invalidating everything when the DPI changed because the underlying renderer will already do that.
## Validation Steps Performed
* [x] Check at 150% DPI. Print text, scroll text down and up, do selection.
* [x] Check at 100% DPI. Print text, scroll text down and up, do selection.
* [x] Span two different DPI monitors and drag between them.
* [x] Giant pile of tests in https://github.com/microsoft/terminal/pull/5345#issuecomment-614127648
Co-authored-by: Dustin Howett <duhowett@microsoft.com>
Co-authored-by: Mike Griese <migrie@microsoft.com>
2020-04-22 23:59:51 +02:00
|
|
|
// This template will convert to size from floating-point args;
|
|
|
|
// a math type is required. If you _don't_ provide one, you're going to
|
|
|
|
// get a compile-time error about "cannot convert from initializer-list to til::size"
|
|
|
|
template<typename TilMath, typename TOther>
|
|
|
|
constexpr size(TilMath, const TOther& width, const TOther& height, std::enable_if_t<std::is_floating_point_v<TOther>, int> /*sentinel*/ = 0) :
|
|
|
|
size(TilMath::template cast<ptrdiff_t>(width), TilMath::template cast<ptrdiff_t>(height))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-03-10 21:51:26 +01:00
|
|
|
constexpr bool operator==(const size& other) const noexcept
|
|
|
|
{
|
|
|
|
return _width == other._width &&
|
|
|
|
_height == other._height;
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr bool operator!=(const size& other) const noexcept
|
|
|
|
{
|
|
|
|
return !(*this == other);
|
|
|
|
}
|
|
|
|
|
2020-03-19 17:12:15 +01:00
|
|
|
constexpr explicit operator bool() const noexcept
|
|
|
|
{
|
|
|
|
return _width > 0 && _height > 0;
|
|
|
|
}
|
|
|
|
|
2020-03-10 21:51:26 +01:00
|
|
|
size operator+(const size& other) const
|
|
|
|
{
|
|
|
|
ptrdiff_t width;
|
|
|
|
THROW_HR_IF(E_ABORT, !base::CheckAdd(_width, other._width).AssignIfValid(&width));
|
|
|
|
|
|
|
|
ptrdiff_t height;
|
|
|
|
THROW_HR_IF(E_ABORT, !base::CheckAdd(_height, other._height).AssignIfValid(&height));
|
|
|
|
|
|
|
|
return size{ width, height };
|
|
|
|
}
|
|
|
|
|
|
|
|
size operator-(const size& other) const
|
|
|
|
{
|
|
|
|
ptrdiff_t width;
|
|
|
|
THROW_HR_IF(E_ABORT, !base::CheckSub(_width, other._width).AssignIfValid(&width));
|
|
|
|
|
|
|
|
ptrdiff_t height;
|
|
|
|
THROW_HR_IF(E_ABORT, !base::CheckSub(_height, other._height).AssignIfValid(&height));
|
|
|
|
|
|
|
|
return size{ width, height };
|
|
|
|
}
|
|
|
|
|
|
|
|
size operator*(const size& other) const
|
|
|
|
{
|
|
|
|
ptrdiff_t width;
|
|
|
|
THROW_HR_IF(E_ABORT, !base::CheckMul(_width, other._width).AssignIfValid(&width));
|
|
|
|
|
|
|
|
ptrdiff_t height;
|
|
|
|
THROW_HR_IF(E_ABORT, !base::CheckMul(_height, other._height).AssignIfValid(&height));
|
|
|
|
|
|
|
|
return size{ width, height };
|
|
|
|
}
|
|
|
|
|
2020-04-13 22:09:02 +02:00
|
|
|
template<typename TilMath>
|
|
|
|
size scale(TilMath, const float scale) const
|
|
|
|
{
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
float Width, Height;
|
|
|
|
} sz;
|
|
|
|
THROW_HR_IF(E_ABORT, !base::CheckMul(scale, _width).AssignIfValid(&sz.Width));
|
|
|
|
THROW_HR_IF(E_ABORT, !base::CheckMul(scale, _height).AssignIfValid(&sz.Height));
|
|
|
|
|
|
|
|
return til::size(TilMath(), sz);
|
|
|
|
}
|
|
|
|
|
2020-03-10 21:51:26 +01:00
|
|
|
size operator/(const size& other) const
|
|
|
|
{
|
|
|
|
ptrdiff_t width;
|
|
|
|
THROW_HR_IF(E_ABORT, !base::CheckDiv(_width, other._width).AssignIfValid(&width));
|
|
|
|
|
|
|
|
ptrdiff_t height;
|
|
|
|
THROW_HR_IF(E_ABORT, !base::CheckDiv(_height, other._height).AssignIfValid(&height));
|
|
|
|
|
|
|
|
return size{ width, height };
|
|
|
|
}
|
|
|
|
|
|
|
|
size divide_ceil(const size& other) const
|
|
|
|
{
|
|
|
|
// Divide normally to get the floor.
|
|
|
|
const size floor = *this / other;
|
|
|
|
|
|
|
|
ptrdiff_t adjWidth = 0;
|
|
|
|
ptrdiff_t adjHeight = 0;
|
|
|
|
|
|
|
|
// Check for width remainder, anything not 0.
|
|
|
|
// If we multiply the floored number with the other, it will equal
|
|
|
|
// the old width if there was no remainder.
|
|
|
|
if (other._width * floor._width != _width)
|
|
|
|
{
|
|
|
|
// If there was any remainder,
|
|
|
|
// Grow the magnitude by 1 in the
|
|
|
|
// direction of the sign.
|
|
|
|
if (floor.width() >= 0)
|
|
|
|
{
|
|
|
|
++adjWidth;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
--adjWidth;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for height remainder, anything not 0.
|
|
|
|
// If we multiply the floored number with the other, it will equal
|
|
|
|
// the old width if there was no remainder.
|
|
|
|
if (other._height * floor._height != _height)
|
|
|
|
{
|
|
|
|
// If there was any remainder,
|
|
|
|
// Grow the magnitude by 1 in the
|
|
|
|
// direction of the sign.
|
|
|
|
if (_height >= 0)
|
|
|
|
{
|
|
|
|
++adjHeight;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
--adjHeight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return floor + size{ adjWidth, adjHeight };
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr ptrdiff_t width() const noexcept
|
|
|
|
{
|
|
|
|
return _width;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
T width() const
|
|
|
|
{
|
|
|
|
T ret;
|
|
|
|
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(width()).AssignIfValid(&ret));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr ptrdiff_t height() const noexcept
|
|
|
|
{
|
|
|
|
return _height;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
T height() const
|
|
|
|
{
|
|
|
|
T ret;
|
|
|
|
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(height()).AssignIfValid(&ret));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptrdiff_t area() const
|
|
|
|
{
|
|
|
|
ptrdiff_t result;
|
|
|
|
THROW_HR_IF(E_ABORT, !base::CheckMul(_width, _height).AssignIfValid(&result));
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
Implement a pair of shims for `cls`, `Clear-Host` in conpty mode (#5627)
## Summary of the Pull Request
This PR implements a pair of shims for `cmd` and `powershell`, so that their `cls` and `Clear-Host` functions will clear the entire terminal buffer (like they do in conhost), instead of just the viewport. With the conpty viewport and buffer being the same size, there's effectively no way to know if an application is calling these API's in this way with the intention of clearing the buffer or the viewport. We absolutely have to guess.
Each of these shims checks to see if the way that the API is being called exactly matches the way `cmd` or `powershell` would call these APIs. If it does, we manually write a `^[[3J` to the connected terminal, to get he Terminal to clear it's own scrollback.
~~_⚠️ If another application were trying to clear the **viewport** with an exactly similar API call, this would also cause the terminal scrollback to get cleared ⚠️_~~
* [x] Should these shims be restricted to when the process that's calling them is actually `cmd.exe` or `powershell.exe`? Can I even do this? I think we've done such a good job of isolating the client process information from the rest of the host code that I can't figure out how to do this.
- YES, this can be done, and I did it.
* [ ] **TODO**: _While I'm here_, should I have `DoSrvPrivateEraseAll` (the implementation for `^[[2J`, in `getset.cpp`) also manually trigger a EraseAll in the terminal in conpty mode?
## PR Checklist
* [x] Closes #3126
* [x] Actually closes #1305 too, which is really the same thing, but probably deserves a callout
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
## Validation Steps Performed
* ran tests
* checked `cls` in the Terminal
* checked `Clear-Host` in the Terminal
* Checked running `powershell clear-host` from `cmd.exe`
2020-04-30 23:53:31 +02:00
|
|
|
template<typename T>
|
|
|
|
T area() const
|
|
|
|
{
|
|
|
|
T ret;
|
|
|
|
THROW_HR_IF(E_ABORT, !base::CheckMul(_width, _height).AssignIfValid(&ret));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-03-10 21:51:26 +01:00
|
|
|
#ifdef _WINCONTYPES_
|
|
|
|
operator COORD() const
|
|
|
|
{
|
|
|
|
COORD ret;
|
|
|
|
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(_width).AssignIfValid(&ret.X));
|
|
|
|
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(_height).AssignIfValid(&ret.Y));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef _WINDEF_
|
|
|
|
operator SIZE() const
|
|
|
|
{
|
|
|
|
SIZE ret;
|
|
|
|
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(_width).AssignIfValid(&ret.cx));
|
|
|
|
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(_height).AssignIfValid(&ret.cy));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef DCOMMON_H_INCLUDED
|
|
|
|
constexpr operator D2D1_SIZE_F() const noexcept
|
|
|
|
{
|
|
|
|
return D2D1_SIZE_F{ gsl::narrow_cast<float>(_width), gsl::narrow_cast<float>(_height) };
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
Move ConPTY to use til::bitmap (#5024)
## Summary of the Pull Request
Moves the ConPTY drawing mechanism (`VtRenderer`) to use the fine-grained `til::bitmap` individual-dirty-bit tracking mechanism instead of coarse-grained rectangle unions to improve drawing performance by dramatically reducing the total area redrawn.
## PR Checklist
* [x] Part of #778 and #1064
* [x] I work here
* [x] Tests added and updated.
* [x] I'm a core contributor
## Detailed Description of the Pull Request / Additional comments
- Converted `GetDirtyArea()` interface from `IRenderEngine` to use a vector of `til::rectangle` instead of the `SMALL_RECT` to banhammer inclusive rectangles.
- `VtEngine` now holds and operates on the `til::bitmap` for invalidation regions. All invalidation operation functions that used to be embedded inside `VtEngine` are deleted in favor of using the ones in `til::bitmap`.
- Updated `VtEngine` tracing to use new `til::bitmap` on trace and the new `to_string()` methods detailed below.
- Comparison operators for `til::bitmap` and complementary tests.
- Fixed an issue where the dirty rectangle shortcut in `til::bitmap` was set to 0,0,0,0 by default which means that `|=` on it with each `set()` operation was stretching the rectangle from 0,0. Now it's a `std::optional` so it has no value after just being cleared and will build from whatever the first invalidated rectangle is. Complementary tests added.
- Optional run caching for `til::bitmap` in the `runs()` method since both VT and DX renderers will likely want to generate the set of runs at the beginning of a frame and refer to them over and over through that frame. Saves the iteration and creation and caches inside `til::bitmap` where the chance of invalidation of the underlying data is known best. It is still possible to iterate manually with `begin()` and `end()` from the outside without caching, if desired. Complementary tests added.
- WEX templates added for `til::bitmap` and used in tests.
- `translate()` method for `til::bitmap` which will slide the dirty points in the direction specified by a `til::point` and optionally back-fill the uncovered area as dirty. Complementary tests added.
- Moves all string generation for `til` types `size`, `point`, `rectangle`, and `some` into a `to_string` method on each object such that it can be used in both ETW tracing scenarios AND in the TAEF templates uniformly. Adds a similar method for `bitmap`.
- Add tagging to `_bitmap_const_iterator` such that it appears as a valid **Input Iterator** to STL collections and can be used in a `std::vector` constructor as a range. Adds and cleans up operators on this iterator to match the theoretical requirements for an **Input Iterator**. Complementary tests added.
- Add loose operators to `til` which will allow some basic math operations (+, -, *, /) between `til::size` and `til::point` and vice versa. Complementary tests added. Complementary tests added.
- Adds operators to `til::rectangle` to allow scaling with basic math operations (+, -, *) versus `til::size` and translation with basic math operations (+, -) against `til::point`. Complementary tests added.
- In-place variants of some operations added to assorted `til` objects. Complementary tests added.
- Update VT tests to compare invalidation against the new map structure instead of raw rectangles where possible.
## Validation Steps Performed
- Wrote additional til Unit Tests for all additional operators and functions added to the project to support this operation
- Updated the existing VT renderer tests
- Ran perf check
2020-03-23 16:57:54 +01:00
|
|
|
std::wstring to_string() const
|
|
|
|
{
|
|
|
|
return wil::str_printf<std::wstring>(L"[W:%td, H:%td]", width(), height());
|
|
|
|
}
|
|
|
|
|
2020-03-10 21:51:26 +01:00
|
|
|
protected:
|
|
|
|
ptrdiff_t _width;
|
|
|
|
ptrdiff_t _height;
|
|
|
|
|
|
|
|
#ifdef UNIT_TESTING
|
|
|
|
friend class ::SizeTests;
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef __WEX_COMMON_H__
|
|
|
|
namespace WEX::TestExecution
|
|
|
|
{
|
|
|
|
template<>
|
|
|
|
class VerifyOutputTraits<::til::size>
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
static WEX::Common::NoThrowString ToString(const ::til::size& size)
|
|
|
|
{
|
Move ConPTY to use til::bitmap (#5024)
## Summary of the Pull Request
Moves the ConPTY drawing mechanism (`VtRenderer`) to use the fine-grained `til::bitmap` individual-dirty-bit tracking mechanism instead of coarse-grained rectangle unions to improve drawing performance by dramatically reducing the total area redrawn.
## PR Checklist
* [x] Part of #778 and #1064
* [x] I work here
* [x] Tests added and updated.
* [x] I'm a core contributor
## Detailed Description of the Pull Request / Additional comments
- Converted `GetDirtyArea()` interface from `IRenderEngine` to use a vector of `til::rectangle` instead of the `SMALL_RECT` to banhammer inclusive rectangles.
- `VtEngine` now holds and operates on the `til::bitmap` for invalidation regions. All invalidation operation functions that used to be embedded inside `VtEngine` are deleted in favor of using the ones in `til::bitmap`.
- Updated `VtEngine` tracing to use new `til::bitmap` on trace and the new `to_string()` methods detailed below.
- Comparison operators for `til::bitmap` and complementary tests.
- Fixed an issue where the dirty rectangle shortcut in `til::bitmap` was set to 0,0,0,0 by default which means that `|=` on it with each `set()` operation was stretching the rectangle from 0,0. Now it's a `std::optional` so it has no value after just being cleared and will build from whatever the first invalidated rectangle is. Complementary tests added.
- Optional run caching for `til::bitmap` in the `runs()` method since both VT and DX renderers will likely want to generate the set of runs at the beginning of a frame and refer to them over and over through that frame. Saves the iteration and creation and caches inside `til::bitmap` where the chance of invalidation of the underlying data is known best. It is still possible to iterate manually with `begin()` and `end()` from the outside without caching, if desired. Complementary tests added.
- WEX templates added for `til::bitmap` and used in tests.
- `translate()` method for `til::bitmap` which will slide the dirty points in the direction specified by a `til::point` and optionally back-fill the uncovered area as dirty. Complementary tests added.
- Moves all string generation for `til` types `size`, `point`, `rectangle`, and `some` into a `to_string` method on each object such that it can be used in both ETW tracing scenarios AND in the TAEF templates uniformly. Adds a similar method for `bitmap`.
- Add tagging to `_bitmap_const_iterator` such that it appears as a valid **Input Iterator** to STL collections and can be used in a `std::vector` constructor as a range. Adds and cleans up operators on this iterator to match the theoretical requirements for an **Input Iterator**. Complementary tests added.
- Add loose operators to `til` which will allow some basic math operations (+, -, *, /) between `til::size` and `til::point` and vice versa. Complementary tests added. Complementary tests added.
- Adds operators to `til::rectangle` to allow scaling with basic math operations (+, -, *) versus `til::size` and translation with basic math operations (+, -) against `til::point`. Complementary tests added.
- In-place variants of some operations added to assorted `til` objects. Complementary tests added.
- Update VT tests to compare invalidation against the new map structure instead of raw rectangles where possible.
## Validation Steps Performed
- Wrote additional til Unit Tests for all additional operators and functions added to the project to support this operation
- Updated the existing VT renderer tests
- Ran perf check
2020-03-23 16:57:54 +01:00
|
|
|
return WEX::Common::NoThrowString(size.to_string().c_str());
|
2020-03-10 21:51:26 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<>
|
|
|
|
class VerifyCompareTraits<::til::size, ::til::size>
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
static bool AreEqual(const ::til::size& expected, const ::til::size& actual) noexcept
|
|
|
|
{
|
|
|
|
return expected == actual;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool AreSame(const ::til::size& expected, const ::til::size& actual) noexcept
|
|
|
|
{
|
|
|
|
return &expected == &actual;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool IsLessThan(const ::til::size& expectedLess, const ::til::size& expectedGreater) = delete;
|
|
|
|
|
|
|
|
static bool IsGreaterThan(const ::til::size& expectedGreater, const ::til::size& expectedLess) = delete;
|
|
|
|
|
|
|
|
static bool IsNull(const ::til::size& object) noexcept
|
|
|
|
{
|
|
|
|
return object == til::size{};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
#endif
|