diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/EditModel.cxx | 9 | ||||
| -rw-r--r-- | src/EditModel.h | 2 | ||||
| -rw-r--r-- | src/EditView.cxx | 200 | ||||
| -rw-r--r-- | src/EditView.h | 6 | ||||
| -rw-r--r-- | src/Editor.cxx | 15 | ||||
| -rw-r--r-- | src/Editor.h | 2 | ||||
| -rw-r--r-- | src/PositionCache.cxx | 103 | ||||
| -rw-r--r-- | src/PositionCache.h | 36 | 
8 files changed, 328 insertions, 45 deletions
| diff --git a/src/EditModel.cxx b/src/EditModel.cxx index fcca51405..e640e05bb 100644 --- a/src/EditModel.cxx +++ b/src/EditModel.cxx @@ -77,3 +77,12 @@ EditModel::~EditModel() {  	pdoc->Release();  	pdoc = 0;  } + +bool EditModel::BidirectionalEnabled() const { +	return (bidirectional != Bidirectional::bidiDisabled) && +		(SC_CP_UTF8 == pdoc->dbcsCodePage); +} + +bool EditModel::BidirectionalR2L() const { +	return bidirectional == Bidirectional::bidiR2L; +} diff --git a/src/EditModel.h b/src/EditModel.h index 7ad719c12..3da6afb58 100644 --- a/src/EditModel.h +++ b/src/EditModel.h @@ -63,6 +63,8 @@ public:  	virtual Point GetVisibleOriginInMain() const = 0;  	virtual Sci::Line LinesOnScreen() const = 0;  	virtual Range GetHotSpotRange() const = 0; +	bool BidirectionalEnabled() const; +	bool BidirectionalR2L() const;  };  } diff --git a/src/EditView.cxx b/src/EditView.cxx index 6ca22e4f2..76edf1c68 100644 --- a/src/EditView.cxx +++ b/src/EditView.cxx @@ -589,8 +589,39 @@ void EditView::LayoutLine(const EditModel &model, Sci::Line line, Surface *surfa  	}  } +// Fill the LineLayout bidirectional data fields according to each char style + +void EditView::UpdateBidiData(const EditModel &model, const ViewStyle &vstyle, LineLayout *ll) { +	if (model.BidirectionalEnabled()) { +		ll->EnsureBidiData(); +		for (int stylesInLine = 0; stylesInLine < ll->numCharsInLine; stylesInLine++) { +			ll->bidiData->stylesFonts[stylesInLine].MakeAlias(vstyle.styles[ll->styles[stylesInLine]].font); +		} +		ll->bidiData->stylesFonts[ll->numCharsInLine].ClearFont(); + +		for (int charsInLine = 0; charsInLine < ll->numCharsInLine; charsInLine++) { +			const int charWidth = UTF8DrawBytes(reinterpret_cast<unsigned char *>(&ll->chars[charsInLine]), ll->numCharsInLine - charsInLine); +			const Representation *repr = model.reprs.RepresentationFromCharacter(&ll->chars[charsInLine], charWidth); + +			ll->bidiData->widthReprs[charsInLine] = 0.0f; +			if (repr && ll->chars[charsInLine] != '\t') { +				ll->bidiData->widthReprs[charsInLine] = ll->positions[charsInLine + charWidth] - ll->positions[charsInLine]; +			} +			if (charWidth > 1) { +				for (int c = 1; c < charWidth; c++) { +					charsInLine++; +					ll->bidiData->widthReprs[charsInLine] = 0.0f; +				} +			} +		} +		ll->bidiData->widthReprs[ll->numCharsInLine] = 0.0f; +	} else { +		ll->bidiData.reset(); +	} +} +  Point EditView::LocationFromPosition(Surface *surface, const EditModel &model, SelectionPosition pos, Sci::Line topLine, -				     const ViewStyle &vs, PointEnd pe) { +				     const ViewStyle &vs, PointEnd pe, const PRectangle rcClient) {  	Point pt;  	if (pos.Position() == INVALID_POSITION)  		return pt; @@ -607,8 +638,28 @@ Point EditView::LocationFromPosition(Surface *surface, const EditModel &model, S  		LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth);  		const int posInLine = static_cast<int>(pos.Position() - posLineStart);  		pt = ll->PointFromPosition(posInLine, vs.lineHeight, pe); -		pt.y += (lineVisible - topLine) * vs.lineHeight;  		pt.x += vs.textStart - model.xOffset; + +		if (model.BidirectionalEnabled()) { +			// Fill the line bidi data +			UpdateBidiData(model, vs, ll); + +			// Find subLine +			const int subLine = ll->SubLineFromPosition(posInLine, pe); +			const int caretPosition = posInLine - ll->LineStart(subLine); + +			// Get the point from current position +			const ScreenLine screenLine(ll, subLine, vs, rcClient.right, tabWidthMinimumPixels); +			pt.x = surface->XFromPosition(&screenLine, caretPosition); + +			pt.x += vs.textStart - model.xOffset; + +			pt.y = 0; +			if (posInLine >= ll->LineStart(subLine)) { +				pt.y = static_cast<XYPOSITION>(subLine*vs.lineHeight); +			} +		} +		pt.y += (lineVisible - topLine) * vs.lineHeight;  	}  	pt.x += pos.VirtualSpace() * vs.styles[ll->EndLineStyle()].spaceWidth;  	return pt; @@ -639,7 +690,8 @@ Range EditView::RangeDisplayLine(Surface *surface, const EditModel &model, Sci::  	return rangeSubLine;  } -SelectionPosition EditView::SPositionFromLocation(Surface *surface, const EditModel &model, PointDocument pt, bool canReturnInvalid, bool charPosition, bool virtualSpace, const ViewStyle &vs) { +SelectionPosition EditView::SPositionFromLocation(Surface *surface, const EditModel &model, PointDocument pt, bool canReturnInvalid, +	bool charPosition, bool virtualSpace, const ViewStyle &vs, const PRectangle rcClient) {  	pt.x = pt.x - vs.textStart;  	Sci::Line visibleLine = static_cast<int>(floor(pt.y / vs.lineHeight));  	if (!canReturnInvalid && (visibleLine < 0)) @@ -661,8 +713,18 @@ SelectionPosition EditView::SPositionFromLocation(Surface *surface, const EditMo  			const XYPOSITION subLineStart = ll->positions[rangeSubLine.start];  			if (subLine > 0)	// Wrapped  				pt.x -= ll->wrapIndent; -			const Sci::Position positionInLine = ll->FindPositionFromX(static_cast<XYPOSITION>(pt.x + subLineStart), -				rangeSubLine, charPosition); +			Sci::Position positionInLine = 0; +			if (model.BidirectionalEnabled()) { +				// Fill the line bidi data +				UpdateBidiData(model, vs, ll); + +				const ScreenLine screenLine(ll, subLine, vs, rcClient.right, tabWidthMinimumPixels); +				positionInLine = surface->PositionFromX(&screenLine, static_cast<XYPOSITION>(pt.x), charPosition) + +					rangeSubLine.start; +			} else { +				positionInLine = ll->FindPositionFromX(static_cast<XYPOSITION>(pt.x + subLineStart), +					rangeSubLine, charPosition); +			}  			if (positionInLine < rangeSubLine.end) {  				return SelectionPosition(model.pdoc->MovePositionOutsideChar(positionInLine + posLineStart, 1));  			} @@ -869,7 +931,7 @@ void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle  		const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth;  		virtualSpace = model.sel.VirtualSpaceFor(model.pdoc->LineEnd(line)) * spaceWidth;  	} -	const XYPOSITION xEol = static_cast<XYPOSITION>(ll->positions[lineEnd] - subLineStart); +	XYPOSITION xEol = static_cast<XYPOSITION>(ll->positions[lineEnd] - subLineStart);  	// Fill the virtual space and show selections within it  	if (virtualSpace > 0.0f) { @@ -1017,27 +1079,51 @@ void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle  }  static void DrawIndicator(int indicNum, Sci::Position startPos, Sci::Position endPos, Surface *surface, const ViewStyle &vsDraw, -	const LineLayout *ll, int xStart, PRectangle rcLine, Sci::Position secondCharacter, int subLine, Indicator::DrawState drawState, int value) { +	const LineLayout *ll, int xStart, PRectangle rcLine, Sci::Position secondCharacter, int subLine, Indicator::DrawState drawState, +	int value, bool bidiEnabled, int tabWidthMinimumPixels) { +  	const XYPOSITION subLineStart = ll->positions[ll->LineStart(subLine)]; + +	std::vector<PRectangle> rectangles; +  	const PRectangle rcIndic(  		ll->positions[startPos] + xStart - subLineStart,  		rcLine.top + vsDraw.maxAscent,  		ll->positions[endPos] + xStart - subLineStart,  		rcLine.top + vsDraw.maxAscent + 3); -	PRectangle rcFirstCharacter = rcIndic; -	// Allow full descent space for character indicators -	rcFirstCharacter.bottom = rcLine.top + vsDraw.maxAscent + vsDraw.maxDescent; -	if (secondCharacter >= 0) { -		rcFirstCharacter.right = ll->positions[secondCharacter] + xStart - subLineStart; + +	if (bidiEnabled) { +		ScreenLine screenLine(ll, subLine, vsDraw, rcLine.right - xStart, tabWidthMinimumPixels); +		const Range lineRange = ll->SubLineRange(subLine, LineLayout::Scope::visibleOnly); + +		std::vector<Interval> intervals = surface->FindRangeIntervals(&screenLine,  +			startPos - lineRange.start, endPos - lineRange.start); +		for (const Interval &interval : intervals) { +			PRectangle rcInterval = rcIndic; +			rcInterval.left = interval.left + xStart; +			rcInterval.right = interval.right + xStart; +			rectangles.push_back(rcInterval); +		}  	} else { -		// Indicator continued from earlier line so make an empty box and don't draw -		rcFirstCharacter.right = rcFirstCharacter.left; +		rectangles.push_back(rcIndic); +	} + +	for (const PRectangle &rc : rectangles) { +		PRectangle rcFirstCharacter = rc; +		// Allow full descent space for character indicators +		rcFirstCharacter.bottom = rcLine.top + vsDraw.maxAscent + vsDraw.maxDescent; +		if (secondCharacter >= 0) { +			rcFirstCharacter.right = ll->positions[secondCharacter] + xStart - subLineStart; +		} else { +			// Indicator continued from earlier line so make an empty box and don't draw +			rcFirstCharacter.right = rcFirstCharacter.left; +		} +		vsDraw.indicators[indicNum].Draw(surface, rc, rcLine, rcFirstCharacter, drawState, value);  	} -	vsDraw.indicators[indicNum].Draw(surface, rcIndic, rcLine, rcFirstCharacter, drawState, value);  }  static void DrawIndicators(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, -	Sci::Line line, int xStart, PRectangle rcLine, int subLine, Sci::Position lineEnd, bool under, Sci::Position hoverIndicatorPos) { +	Sci::Line line, int xStart, PRectangle rcLine, int subLine, Sci::Position lineEnd, bool under, int tabWidthMinimumPixels) {  	// Draw decorators  	const Sci::Position posLineStart = model.pdoc->LineStart(line);  	const Sci::Position lineStart = ll->LineStart(subLine); @@ -1053,12 +1139,13 @@ static void DrawIndicators(Surface *surface, const EditModel &model, const ViewS  				const Range rangeRun(deco->StartRun(startPos), deco->EndRun(startPos));  				const Sci::Position endPos = std::min(rangeRun.end, posLineEnd);  				const bool hover = vsDraw.indicators[deco->Indicator()].IsDynamic() && -					rangeRun.ContainsCharacter(hoverIndicatorPos); +					rangeRun.ContainsCharacter(model.hoverIndicatorPos);  				const int value = deco->ValueAt(startPos);  				const Indicator::DrawState drawState = hover ? Indicator::drawHover : Indicator::drawNormal;  				const Sci::Position posSecond = model.pdoc->MovePositionOutsideChar(rangeRun.First() + 1, 1);  				DrawIndicator(deco->Indicator(), startPos - posLineStart, endPos - posLineStart, -					surface, vsDraw, ll, xStart, rcLine, posSecond - posLineStart, subLine, drawState, value); +					surface, vsDraw, ll, xStart, rcLine, posSecond - posLineStart, subLine, drawState, +					value, model.BidirectionalEnabled(), tabWidthMinimumPixels);  				startPos = endPos;  				if (!deco->ValueAt(startPos)) {  					startPos = deco->EndRun(startPos); @@ -1077,14 +1164,16 @@ static void DrawIndicators(Surface *surface, const EditModel &model, const ViewS  				const Sci::Position braceOffset = model.braces[0] - posLineStart;  				if (braceOffset < ll->numCharsInLine) {  					const Sci::Position secondOffset = model.pdoc->MovePositionOutsideChar(model.braces[0] + 1, 1) - posLineStart; -					DrawIndicator(braceIndicator, braceOffset, braceOffset + 1, surface, vsDraw, ll, xStart, rcLine, secondOffset, subLine, Indicator::drawNormal, 1); +					DrawIndicator(braceIndicator, braceOffset, braceOffset + 1, surface, vsDraw, ll, xStart, rcLine, secondOffset, +						subLine, Indicator::drawNormal, 1, model.BidirectionalEnabled(), tabWidthMinimumPixels);  				}  			}  			if (rangeLine.ContainsCharacter(model.braces[1])) {  				const Sci::Position braceOffset = model.braces[1] - posLineStart;  				if (braceOffset < ll->numCharsInLine) {  					const Sci::Position secondOffset = model.pdoc->MovePositionOutsideChar(model.braces[1] + 1, 1) - posLineStart; -					DrawIndicator(braceIndicator, braceOffset, braceOffset + 1, surface, vsDraw, ll, xStart, rcLine, secondOffset, subLine, Indicator::drawNormal, 1); +					DrawIndicator(braceIndicator, braceOffset, braceOffset + 1, surface, vsDraw, ll, xStart, rcLine, secondOffset, +						subLine, Indicator::drawNormal, 1, model.BidirectionalEnabled(), tabWidthMinimumPixels);  				}  			}  		} @@ -1334,6 +1423,17 @@ void EditView::DrawCarets(Surface *surface, const EditModel &model, const ViewSt  		const XYPOSITION virtualOffset = posCaret.VirtualSpace() * spaceWidth;  		if (ll->InLine(offset, subLine) && offset <= ll->numCharsBeforeEOL) {  			XYPOSITION xposCaret = ll->positions[offset] + virtualOffset - ll->positions[ll->LineStart(subLine)]; +			if (model.BidirectionalEnabled() && (posCaret.VirtualSpace() == 0)) { +				// Get caret point +				const ScreenLine screenLine(ll, subLine, vsDraw, rcLine.right, tabWidthMinimumPixels); + +				const int caretPosition = static_cast<int>(posCaret.Position() - posLineStart - ll->LineStart(subLine)); + +				const XYPOSITION caretLeft = surface->XFromPosition(&screenLine, caretPosition); + +				// In case of start of line, the cursor should be at the right +				xposCaret = caretLeft + virtualOffset; +			}  			if (ll->wrapIndent != 0) {  				const Sci::Position lineStart = ll->LineStart(subLine);  				if (lineStart != 0)	// Wrapped @@ -1549,8 +1649,9 @@ static void DrawMarkUnderline(Surface *surface, const EditModel &model, const Vi  		marks >>= 1;  	}  } +  static void DrawTranslucentSelection(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, -	Sci::Line line, PRectangle rcLine, int subLine, Range lineRange, int xStart) { +	Sci::Line line, PRectangle rcLine, int subLine, Range lineRange, int xStart, int tabWidthMinimumPixels) {  	if ((vsDraw.selAlpha != SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha != SC_ALPHA_NOALPHA)) {  		const Sci::Position posLineStart = model.pdoc->LineStart(line);  		const XYACCUMULATOR subLineStart = ll->positions[lineRange.start]; @@ -1567,20 +1668,37 @@ static void DrawTranslucentSelection(Surface *surface, const EditModel &model, c  			if (alpha != SC_ALPHA_NOALPHA) {  				const SelectionSegment portion = model.sel.Range(r).Intersect(virtualSpaceRange);  				if (!portion.Empty()) { -					const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; -					PRectangle rcSegment = rcLine; -					rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - -						static_cast<XYPOSITION>(subLineStart)+portion.start.VirtualSpace() * spaceWidth; -					rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - -						static_cast<XYPOSITION>(subLineStart)+portion.end.VirtualSpace() * spaceWidth; -					if ((ll->wrapIndent != 0) && (lineRange.start != 0)) { -						if ((portion.start.Position() - posLineStart) == lineRange.start && model.sel.Range(r).ContainsCharacter(portion.start.Position() - 1)) -							rcSegment.left -= static_cast<int>(ll->wrapIndent); // indentation added to xStart was truncated to int, so we do the same here +					if (model.BidirectionalEnabled()) { +						const int selectionStart = static_cast<int>(portion.start.Position() - posLineStart - lineRange.start); +						const int selectionEnd = static_cast<int>(portion.end.Position() - posLineStart - lineRange.start); + +						const ColourDesired background = SelectionBackground(vsDraw, r == model.sel.Main(), model.primarySelection); + +						const ScreenLine screenLine(ll, subLine, vsDraw, rcLine.right, tabWidthMinimumPixels); + +						const std::vector<Interval> intervals = surface->FindRangeIntervals(&screenLine, selectionStart, selectionEnd); +						for (const Interval &interval : intervals) { +							const XYPOSITION rcRight = interval.right + xStart; +							const XYPOSITION rcLeft = interval.left + xStart; +							const PRectangle rcSelection(rcLeft, rcLine.top, rcRight, rcLine.bottom); +							SimpleAlphaRectangle(surface, rcSelection, background, alpha); +						} +					} else { +						const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; +						PRectangle rcSegment = rcLine; +						rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - +							static_cast<XYPOSITION>(subLineStart) + portion.start.VirtualSpace() * spaceWidth; +						rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - +							static_cast<XYPOSITION>(subLineStart) + portion.end.VirtualSpace() * spaceWidth; +						if ((ll->wrapIndent != 0) && (lineRange.start != 0)) { +							if ((portion.start.Position() - posLineStart) == lineRange.start && model.sel.Range(r).ContainsCharacter(portion.start.Position() - 1)) +								rcSegment.left -= static_cast<int>(ll->wrapIndent); // indentation added to xStart was truncated to int, so we do the same here +						} +						rcSegment.left = (rcSegment.left > rcLine.left) ? rcSegment.left : rcLine.left; +						rcSegment.right = (rcSegment.right < rcLine.right) ? rcSegment.right : rcLine.right; +						if (rcSegment.right > rcLine.left) +							SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, r == model.sel.Main(), model.primarySelection), alpha);  					} -					rcSegment.left = (rcSegment.left > rcLine.left) ? rcSegment.left : rcLine.left; -					rcSegment.right = (rcSegment.right < rcLine.right) ? rcSegment.right : rcLine.right; -					if (rcSegment.right > rcLine.left) -						SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, r == model.sel.Main(), model.primarySelection), alpha);  				}  			}  		} @@ -1904,7 +2022,8 @@ void EditView::DrawLine(Surface *surface, const EditModel &model, const ViewStyl  		}  		if (phase & drawIndicatorsBack) { -			DrawIndicators(surface, model, vsDraw, ll, line, xStart, rcLine, subLine, lineRangeIncludingEnd.end, true, model.hoverIndicatorPos); +			DrawIndicators(surface, model, vsDraw, ll, line, xStart, rcLine, subLine, +				lineRangeIncludingEnd.end, true, tabWidthMinimumPixels);  			DrawEdgeLine(surface, vsDraw, ll, rcLine, lineRange, xStart);  			DrawMarkUnderline(surface, model, vsDraw, line, rcLine);  		} @@ -1920,7 +2039,8 @@ void EditView::DrawLine(Surface *surface, const EditModel &model, const ViewStyl  	}  	if (phase & drawIndicatorsFore) { -		DrawIndicators(surface, model, vsDraw, ll, line, xStart, rcLine, subLine, lineRangeIncludingEnd.end, false, model.hoverIndicatorPos); +		DrawIndicators(surface, model, vsDraw, ll, line, xStart, rcLine, subLine, +			lineRangeIncludingEnd.end, false, tabWidthMinimumPixels);  	}  	DrawFoldDisplayText(surface, model, vsDraw, ll, line, xStart, rcLine, subLine, subLineStart, phase); @@ -1935,7 +2055,7 @@ void EditView::DrawLine(Surface *surface, const EditModel &model, const ViewStyl  	}  	if (!hideSelection && (phase & drawSelectionTranslucent)) { -		DrawTranslucentSelection(surface, model, vsDraw, ll, line, rcLine, subLine, lineRange, xStart); +		DrawTranslucentSelection(surface, model, vsDraw, ll, line, rcLine, subLine, lineRange, xStart, tabWidthMinimumPixels);  	}  	if (phase & drawLineTranslucent) { @@ -1984,6 +2104,7 @@ void EditView::PaintText(Surface *surfaceWindow, const EditModel &model, PRectan  		}  		surface->SetUnicodeMode(SC_CP_UTF8 == model.pdoc->dbcsCodePage);  		surface->SetDBCSMode(model.pdoc->dbcsCodePage); +		surface->SetBidiR2L(model.BidirectionalR2L());  		const Point ptOrigin = model.GetVisibleOriginInMain(); @@ -2082,6 +2203,11 @@ void EditView::PaintText(Surface *surfaceWindow, const EditModel &model, PRectan  						surface->FillRectangle(rcSpacer, vsDraw.styles[STYLE_DEFAULT].back);  					} +					if (model.BidirectionalEnabled()) { +						// Fill the line bidi data +						UpdateBidiData(model, vsDraw, ll); +					} +  					DrawLine(surface, model, vsDraw, ll, lineDoc, visibleLine, xStart, rcLine, subLine, phase);  #if defined(TIME_PAINTING)  					durPaint += ep.Duration(true); diff --git a/src/EditView.h b/src/EditView.h index 51e2a1e53..16da4e904 100644 --- a/src/EditView.h +++ b/src/EditView.h @@ -116,11 +116,13 @@ public:  	void LayoutLine(const EditModel &model, Sci::Line line, Surface *surface, const ViewStyle &vstyle,  		LineLayout *ll, int width = LineLayout::wrapWidthInfinite); +	void UpdateBidiData(const EditModel &model, const ViewStyle &vstyle, LineLayout *ll); +  	Point LocationFromPosition(Surface *surface, const EditModel &model, SelectionPosition pos, Sci::Line topLine, -				   const ViewStyle &vs, PointEnd pe); +		const ViewStyle &vs, PointEnd pe, const PRectangle rcClient);  	Range RangeDisplayLine(Surface *surface, const EditModel &model, Sci::Line lineVisible, const ViewStyle &vs);  	SelectionPosition SPositionFromLocation(Surface *surface, const EditModel &model, PointDocument pt, bool canReturnInvalid, -		bool charPosition, bool virtualSpace, const ViewStyle &vs); +		bool charPosition, bool virtualSpace, const ViewStyle &vs, const PRectangle rcClient);  	SelectionPosition SPositionFromLineX(Surface *surface, const EditModel &model, Sci::Line lineDoc, int x, const ViewStyle &vs);  	Sci::Line DisplayFromPosition(Surface *surface, const EditModel &model, Sci::Position pos, const ViewStyle &vs);  	Sci::Position StartEndDisplayLine(Surface *surface, const EditModel &model, Sci::Position pos, bool start, const ViewStyle &vs); diff --git a/src/Editor.cxx b/src/Editor.cxx index 04d61bea6..9e81a2ef3 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -377,9 +377,10 @@ SelectionPosition Editor::ClampPositionIntoDocument(SelectionPosition sp) const  }  Point Editor::LocationFromPosition(SelectionPosition pos, PointEnd pe) { +	const PRectangle rcClient = GetTextRectangle();  	RefreshStyleData();  	AutoSurface surface(this); -	return view.LocationFromPosition(surface, *this, pos, topLine, vs, pe); +	return view.LocationFromPosition(surface, *this, pos, topLine, vs, pe, rcClient);  }  Point Editor::LocationFromPosition(Sci::Position pos, PointEnd pe) { @@ -395,11 +396,12 @@ SelectionPosition Editor::SPositionFromLocation(Point pt, bool canReturnInvalid,  	RefreshStyleData();  	AutoSurface surface(this); +	PRectangle rcClient = GetTextRectangle(); +	// May be in scroll view coordinates so translate back to main view +	const Point ptOrigin = GetVisibleOriginInMain(); +	rcClient.Move(-ptOrigin.x, -ptOrigin.y); +  	if (canReturnInvalid) { -		PRectangle rcClient = GetTextRectangle(); -		// May be in scroll view coordinates so translate back to main view -		const Point ptOrigin = GetVisibleOriginInMain(); -		rcClient.Move(-ptOrigin.x, -ptOrigin.y);  		if (!rcClient.Contains(pt))  			return SelectionPosition(INVALID_POSITION);  		if (pt.x < vs.textStart) @@ -408,7 +410,8 @@ SelectionPosition Editor::SPositionFromLocation(Point pt, bool canReturnInvalid,  			return SelectionPosition(INVALID_POSITION);  	}  	const PointDocument ptdoc = DocumentPointFromView(pt); -	return view.SPositionFromLocation(surface, *this, ptdoc, canReturnInvalid, charPosition, virtualSpace, vs); +	return view.SPositionFromLocation(surface, *this, ptdoc, canReturnInvalid, +		charPosition, virtualSpace, vs, rcClient);  }  Sci::Position Editor::PositionFromLocation(Point pt, bool canReturnInvalid, bool charPosition) { diff --git a/src/Editor.h b/src/Editor.h index bc295260e..3c21ee092 100644 --- a/src/Editor.h +++ b/src/Editor.h @@ -618,6 +618,7 @@ public:  			surf->Init(ed->wMain.GetID());  			surf->SetUnicodeMode(SC_CP_UTF8 == ed->CodePage());  			surf->SetDBCSMode(ed->CodePage()); +			surf->SetBidiR2L(ed->BidirectionalR2L());  		}  	}  	AutoSurface(SurfaceID sid, Editor *ed, int technology = -1) { @@ -626,6 +627,7 @@ public:  			surf->Init(sid, ed->wMain.GetID());  			surf->SetUnicodeMode(SC_CP_UTF8 == ed->CodePage());  			surf->SetDBCSMode(ed->CodePage()); +			surf->SetBidiR2L(ed->BidirectionalR2L());  		}  	}  	// Deleted so AutoSurface objects can not be copied. diff --git a/src/PositionCache.cxx b/src/PositionCache.cxx index 31a8601f5..b218c39e0 100644 --- a/src/PositionCache.cxx +++ b/src/PositionCache.cxx @@ -46,6 +46,11 @@  using namespace Scintilla; +void BidiData::Resize(size_t maxLineLength_) { +	stylesFonts.resize(maxLineLength_ + 1); +	widthReprs.resize(maxLineLength_ + 1); +} +  LineLayout::LineLayout(int maxLineLength_) :  	lenLineStarts(0),  	lineNumber(-1), @@ -79,15 +84,27 @@ void LineLayout::Resize(int maxLineLength_) {  		// Extra position allocated as sometimes the Windows  		// GetTextExtentExPoint API writes an extra element.  		positions = std::make_unique<XYPOSITION []>(maxLineLength_ + 1 + 1); +		if (bidiData) { +			bidiData->Resize(maxLineLength_); +		} +  		maxLineLength = maxLineLength_;  	}  } +void LineLayout::EnsureBidiData() { +	if (!bidiData) { +		bidiData = std::make_unique<BidiData>(); +		bidiData->Resize(maxLineLength); +	} +} +  void LineLayout::Free() {  	chars.reset();  	styles.reset();  	positions.reset();  	lineStarts.reset(); +	bidiData.reset();  }  void LineLayout::Invalidate(validLevel validity_) { @@ -105,6 +122,16 @@ int LineLayout::LineStart(int line) const {  	}  } +int Scintilla::LineLayout::LineLength(int line) const { +	if (!lineStarts) { +		return numCharsInLine; +	} if (line >= lines - 1) { +		return numCharsInLine - lineStarts[line]; +	} else { +		return lineStarts[line + 1] - lineStarts[line]; +	} +} +  int LineLayout::LineLastVisible(int line, Scope scope) const {  	if (line < 0) {  		return 0; @@ -124,6 +151,25 @@ bool LineLayout::InLine(int offset, int line) const {  		((offset == numCharsInLine) && (line == (lines-1)));  } +int LineLayout::SubLineFromPosition(int posInLine, PointEnd pe) const { +	if (!lineStarts || (posInLine > maxLineLength)) { +		return lines - 1; +	} + +	for (int line = 0; line < lines; line++) { +		if (pe & peSubLineEnd) { +			// Return subline not start of next +			if (lineStarts[line + 1] <= posInLine + 1) +				return line; +		} else { +			if (lineStarts[line + 1] <= posInLine) +				return line; +		} +	} + +	return lines - 1; +} +  void LineLayout::SetLineStart(int line, int start) {  	if ((line >= lenLineStarts) && (line != 0)) {  		const int newMaxLines = line + 20; @@ -244,6 +290,63 @@ int LineLayout::EndLineStyle() const {  	return styles[numCharsBeforeEOL > 0 ? numCharsBeforeEOL-1 : 0];  } +ScreenLine::ScreenLine( +	const LineLayout *ll_, +	int subLine, +	const ViewStyle &vs, +	XYPOSITION width_, +	int tabWidthMinimumPixels_) : +	ll(ll_), +	start(ll->LineStart(subLine)), +	len(ll->LineLength(subLine)), +	width(width_), +	height(static_cast<float>(vs.lineHeight)), +	ctrlCharPadding(vs.ctrlCharPadding), +	tabWidth(vs.tabWidth), +	tabWidthMinimumPixels(tabWidthMinimumPixels_) { +} + +ScreenLine::~ScreenLine() { +} + +std::string_view ScreenLine::Text() const { +	return std::string_view(&ll->chars[start], len); +} + +size_t ScreenLine::Length() const { +	return len; +} + +size_t ScreenLine::RepresentationCount() const { +	return std::count_if(&ll->bidiData->widthReprs[start], +		&ll->bidiData->widthReprs[start + len], +		[](XYPOSITION w) {return w > 0.0f; }); +} + +XYPOSITION ScreenLine::Width() const { +	return width; +} + +XYPOSITION ScreenLine::Height() const { +	return height; +} + +XYPOSITION ScreenLine::TabWidth() const { +	return tabWidth; +} + +XYPOSITION ScreenLine::TabWidthMinimumPixels() const { +	return static_cast<XYPOSITION>(tabWidthMinimumPixels); +} + +const Font *ScreenLine::FontOfPosition(size_t position) const { +	return &ll->bidiData->stylesFonts[start + position]; +} + +XYPOSITION ScreenLine::RepresentationWidth(size_t position) const { +	return ll->bidiData->widthReprs[start + position]; +} +  LineLayoutCache::LineLayoutCache() :  	level(0),  	allInvalidated(false), styleClock(-1), useCount(0) { diff --git a/src/PositionCache.h b/src/PositionCache.h index 7f50c4dec..512ec13f5 100644 --- a/src/PositionCache.h +++ b/src/PositionCache.h @@ -40,6 +40,13 @@ enum PointEnd {  	peSubLineEnd = 0x2  }; +class BidiData { +public: +	std::vector<FontAlias> stylesFonts; +	std::vector<XYPOSITION> widthReprs; +	void Resize(size_t maxLineLength_); +}; +  /**   */  class LineLayout { @@ -66,6 +73,8 @@ public:  	std::unique_ptr<XYPOSITION[]> positions;  	char bracePreviousStyles[2]; +	std::unique_ptr<BidiData> bidiData; +  	// Hotspot support  	Range hotspot; @@ -82,13 +91,16 @@ public:  	void operator=(LineLayout &&) = delete;  	virtual ~LineLayout();  	void Resize(int maxLineLength_); +	void EnsureBidiData();  	void Free();  	void Invalidate(validLevel validity_);  	int LineStart(int line) const; +	int LineLength(int line) const;  	enum class Scope { visibleOnly, includeEnd };  	int LineLastVisible(int line, Scope scope) const;  	Range SubLineRange(int subLine, Scope scope) const;  	bool InLine(int offset, int line) const; +	int SubLineFromPosition(int posInLine, PointEnd pe) const;  	void SetLineStart(int line, int start);  	void SetBracesHighlight(Range rangeLine, const Sci::Position braces[],  		char bracesMatchStyle, int xHighlight, bool ignoreStyle); @@ -99,6 +111,30 @@ public:  	int EndLineStyle() const;  }; +struct ScreenLine : public IScreenLine { +	const LineLayout *ll; +	size_t start; +	size_t len; +	XYPOSITION width; +	XYPOSITION height; +	int ctrlCharPadding; +	XYPOSITION tabWidth; +	int tabWidthMinimumPixels; + +	ScreenLine(const LineLayout *ll_, int subLine, const ViewStyle &vs, XYPOSITION width_, int tabWidthMinimumPixels_); +	virtual ~ScreenLine(); + +	std::string_view Text() const override; +	size_t Length() const override; +	size_t RepresentationCount() const override; +	XYPOSITION Width() const override; +	XYPOSITION Height() const override; +	XYPOSITION TabWidth() const override; +	XYPOSITION TabWidthMinimumPixels() const override; +	const Font *FontOfPosition(size_t position) const override; +	XYPOSITION RepresentationWidth(size_t position) const override; +}; +  /**   */  class LineLayoutCache { | 
