Disable useless scrollbars
[MacVim.git] / src / MacVim / MMTypesetter.m
blob56ee878f95f7da45deda544dd33d6985e6f4dcb1
1 /* vi:set ts=8 sts=4 sw=4 ft=objc:
2  *
3  * VIM - Vi IMproved            by Bram Moolenaar
4  *                              MacVim GUI port by Bjorn Winckler
5  *
6  * Do ":help uganda"  in Vim to read copying and usage conditions.
7  * Do ":help credits" in Vim to see a list of people who contributed.
8  * See README.txt for an overview of the Vim source code.
9  */
11 #import "MMTypesetter.h"
12 #import "MMTextStorage.h"
13 #import "MacVim.h"
16 // The 'linerange' functions count U+2028 and U+2029 as line end characters,
17 // which causes rendering to be screwed up because Vim does not count them as
18 // line end characters.
19 #define MM_USE_LINERANGE 0
22 #if 0
23 @interface MMTypesetter (Private)
24 - (NSCharacterSet *)hiddenCharSet;
25 @end
26 #endif
30 @implementation MMTypesetter
33 // Layout glyphs so that each line fragment has a fixed size.
35 // It is assumed that the font for each character has been chosen so that every
36 // glyph has the right advancement (either 2*cellSize.width or half that,
37 // depending on whether it is a wide character or not).  This is taken care of
38 // by MMTextStorage in setAttributes:range: and in setFont:.  All that is left
39 // for the typesetter to do is to make sure each line fragment has the same
40 // height and that unwanted glyphs are hidden.
42 - (void)layoutGlyphsInLayoutManager:(NSLayoutManager *)lm
43                startingAtGlyphIndex:(unsigned)startGlyphIdx
44            maxNumberOfLineFragments:(unsigned)maxNumLines
45                      nextGlyphIndex:(unsigned *)nextGlyph
47     // TODO: Check that it really is an MMTextStorage.
48     MMTextStorage *ts = (MMTextStorage*)[lm textStorage];
49     NSTextView *tv = [lm firstTextView];
50     NSTextContainer *tc = [tv textContainer];
51     NSFont *font = [ts font];
52     NSString *text = [ts string];
53     unsigned textLen = [text length];
54     NSSize cellSize = [ts cellSize];
55     // NOTE: With non-zero linespace the baseline is adjusted so that the text
56     // is centered within a line.
57     float baseline = [font descender] - floor(.5*[ts linespace]);
59     if (!(lm && ts && tv && tc && font && text && textLen
60                 && [lm isValidGlyphIndex:startGlyphIdx]))
61         return;
63     float baselineOffset = [[NSUserDefaults standardUserDefaults]
64             floatForKey:MMBaselineOffsetKey];
66     baseline += baselineOffset;
68     unsigned startCharIdx = [lm characterIndexForGlyphAtIndex:startGlyphIdx];
69     unsigned i, numberOfLines = 0, firstLine = 0;
70     NSRange firstLineRange = { 0, 0 };
72 #if MM_USE_LINERANGE
73     // Find the first line and its range, and count the number of lines.  (This
74     // info could also be gleaned from MMTextStorage, but we do it here anyway
75     // to make absolutely sure everything is right.)
76     for (i = 0; i < textLen; numberOfLines++) {
77         NSRange lineRange = [text lineRangeForRange:NSMakeRange(i, 0)];
78         if (NSLocationInRange(startCharIdx, lineRange)) {
79             firstLine = numberOfLines;
80             firstLineRange = lineRange;
81         }
83         i = NSMaxRange(lineRange);
84     }
85 #else
86     unsigned stride = 1 + [ts actualColumns];
87     numberOfLines = [ts actualRows];
88     firstLine = (unsigned)(startCharIdx/stride);
89     firstLineRange.location =  firstLine * stride;
90     unsigned len = [text length] - firstLineRange.location;
91     firstLineRange.length = len < stride ? len : stride;
92 #endif
94     // Perform line fragment generation one line at a time.
95     NSRange lineRange = firstLineRange;
96     unsigned endGlyphIdx = startGlyphIdx;
97     for (i = 0; i < maxNumLines && lineRange.length; ++i) {
98         NSRange glyphRange = [lm glyphRangeForCharacterRange:lineRange
99                                         actualCharacterRange:nil];
100         NSRect lineRect = { 0, (firstLine+i)*cellSize.height,
101                 cellSize.width*(lineRange.length-1), cellSize.height };
102         unsigned endLineIdx = NSMaxRange(lineRange);
103         NSPoint glyphPt = { 0, cellSize.height+baseline };
104         unsigned j;
106         endGlyphIdx = NSMaxRange(glyphRange);
108         [lm setTextContainer:tc forGlyphRange:glyphRange];
109         [lm setLineFragmentRect:lineRect forGlyphRange:glyphRange
110                        usedRect:lineRect];
111         [lm setLocation:glyphPt forStartOfGlyphRange:glyphRange];
113         // Hide end-of-line and non-zero space characters (there is one after
114         // every wide character).
115         for (j = lineRange.location; j < endLineIdx; ++j) {
116             unichar ch = [text characterAtIndex:j];
117             if (ch == 0x200b || ch == '\n') {
118                 NSRange range = { j, 1 };
119                 range = [lm glyphRangeForCharacterRange:range
120                                    actualCharacterRange:nil];
121                 [lm setNotShownAttribute:YES forGlyphAtIndex:range.location];
122             }
123         }
125 #if MM_USE_LINERANGE
126         lineRange = [text lineRangeForRange:NSMakeRange(endLineIdx, 0)];
127 #else
128         lineRange.location = endLineIdx;
129         len = [text length] - lineRange.location;
130         if (len < lineRange.length)
131             lineRange.length = len;
132 #endif
133     }
135     if (nextGlyph)
136         *nextGlyph = endGlyphIdx;
139 @end // MMTypesetter
144 #if 0
145 @implementation MMTypesetter (Private)
147 - (NSCharacterSet *)hiddenCharSet
149     static NSCharacterSet *hiddenCharSet = nil;
151     if (!hiddenCharSet) {
152         NSString *string = [NSString stringWithFormat:@"%C\n", 0x200b];
153         hiddenCharSet = [NSCharacterSet
154                 characterSetWithCharactersInString:string];
155         [hiddenCharSet retain];
156     }
158     return hiddenCharSet;
161 @end // MMTypesetter (Private)
162 #endif