#10477: Handle things above U+FFFF in GDI renderer (#10580)

<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Implementation of #10477 - handle surrogate pairs in GDI renderer.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [ ] Closes #10477
* [x] CLA signed.
* [ ] Tests added/passed
* [ ] Documentation updated.
* [ ] Schema updated.
* [x] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #10477

<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
### Why not let Windows draw surrogate pairs? It can do that.

Basically, the comment says everything:
c90de69250/src/renderer/gdi/paint.cpp (L346-L347)

However, handling things above U+FFFF doesn't really require extra effort. It's enough to:
- Put *all* characters to the output buffer
- Set the first width to cluster width and the rest to 0
- Sit back and relax while Windows does the rest

<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
```CMD
@echo off
chcp 65001

echo 𠜎𠝹𠱓𠱸𠲖𠳏𠳕𠴕𠵼𠵿𠸎
echo 👨👩👧👦
```
Save this as a UTF-8 cmd file and run.

### Before the change
![image](https://user-images.githubusercontent.com/11453922/122832196-ed438880-d2e2-11eb-93dd-931954efedbf.png)

### After the change
![image](https://user-images.githubusercontent.com/11453922/122832217-f2a0d300-d2e2-11eb-99f0-e129e5544667.png)

An example of a third party app working with surrogate pairs in a patched OpenConsole:
![image](https://user-images.githubusercontent.com/11453922/122838225-837cac00-d2ed-11eb-8faf-dbeb52f77916.png)

As discussed, this change doesn't claim to be the full support for surrogate pairs (there are still corner cases possible), but brings it on par with Terminal with minimal effort.
This commit is contained in:
Alex Alabuzhev
2021-07-08 16:35:11 +01:00
committed by GitHub
parent d6da6ba353
commit cdecfcd67f

View File

@@ -328,11 +328,13 @@ using namespace Microsoft::Console::Render;
const auto pPolyTextLine = &_pPolyText[_cPolyText];
auto& polyString = _polyStrings.emplace_back(cchLine, UNICODE_NULL);
auto& polyString = _polyStrings.emplace_back();
polyString.reserve(cchLine);
COORD const coordFontSize = _GetFontSize();
auto& polyWidth = _polyWidths.emplace_back(cchLine, 0);
auto& polyWidth = _polyWidths.emplace_back();
polyWidth.reserve(cchLine);
// Sum up the total widths the entire line/run is expected to take while
// copying the pixel widths into a structure to direct GDI how many pixels to use per character.
@@ -343,11 +345,11 @@ using namespace Microsoft::Console::Render;
{
const auto& cluster = til::at(clusters, i);
// Our GDI renderer hasn't and isn't going to handle things above U+FFFF or sequences.
// So replace anything complicated with a replacement character for drawing purposes.
polyString[i] = cluster.GetTextAsSingle();
polyWidth[i] = gsl::narrow<int>(cluster.GetColumns()) * coordFontSize.X;
cchCharWidths += polyWidth[i];
const auto text = cluster.GetText();
polyString += text;
polyWidth.push_back(gsl::narrow<int>(cluster.GetColumns()) * coordFontSize.X);
cchCharWidths += polyWidth.back();
polyWidth.append(text.size() - 1, 0);
}
// Detect and convert for raster font...
@@ -396,7 +398,7 @@ using namespace Microsoft::Console::Render;
const auto bottomOffset = _currentLineRendition == LineRendition::DoubleHeightTop ? halfHeight : 0;
pPolyTextLine->lpstr = polyString.data();
pPolyTextLine->n = gsl::narrow<UINT>(clusters.size());
pPolyTextLine->n = gsl::narrow<UINT>(polyString.size());
pPolyTextLine->x = ptDraw.x;
pPolyTextLine->y = ptDraw.y;
pPolyTextLine->uiFlags = ETO_OPAQUE | ETO_CLIPPED;