Skip to content

Commit

Permalink
#10477: Handle things above U+FFFF in GDI renderer (#10580)
Browse files Browse the repository at this point in the history
<!-- 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:
https://github.com/microsoft/terminal/blob/c90de692509b074bfde191910d67154cfe389911/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.
  • Loading branch information
alabuzhev authored Jul 8, 2021
1 parent d6da6ba commit cdecfcd
Showing 1 changed file with 10 additions and 8 deletions.
18 changes: 10 additions & 8 deletions src/renderer/gdi/paint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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...
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit cdecfcd

Please sign in to comment.