Skip to content

Commit

Permalink
Fixed a few more printer formatting bugs.
Browse files Browse the repository at this point in the history
  • Loading branch information
alinebee committed Nov 6, 2012
1 parent 53ac901 commit d5a2757
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 44 deletions.
7 changes: 4 additions & 3 deletions Boxer/BXSession+BXPrinting.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
#import "BXPrintSession.h"
#import <Quartz/Quartz.h>

@interface PDFDocument (HiddenMethods)
@interface PDFDocument (PDFDocumentPrivate)

- (NSPrintOperation *) getPrintOperationForPrintInfo: (NSPrintInfo *)printInfo autoRotate: (BOOL)autoRotate;
- (NSPrintOperation *) getPrintOperationForPrintInfo: (NSPrintInfo *)printInfo
autoRotate: (BOOL)autoRotate;

@end

Expand Down Expand Up @@ -47,7 +48,7 @@ - (void) _createPreviewWindowForPrinter: (BXEmulatedPrinter *)printer

- (void) printerDidInitialize: (BXEmulatedPrinter *)printer
{
if (NO && !_printPreview)
if (!_printPreview)
[self _createPreviewWindowForPrinter: printer];
}

Expand Down
126 changes: 85 additions & 41 deletions Boxer/Printing/BXEmulatedPrinter.mm
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ @interface BXEmulatedPrinter ()
//The actual width of one monospace character at the current pitch, in inches.
@property (readonly, nonatomic) double effectiveCharacterWidth;

//The actual extra spacing to insert between characters.
//This will be the same as letterSpacing unless one of the double-width modes
//is active, in which case it will be doubled also.
@property (readonly, nonatomic) double effectiveLetterSpacing;


#pragma mark -
#pragma mark Helper class methods
Expand Down Expand Up @@ -374,6 +379,28 @@ - (void) setSuperscript: (BOOL)flag
}
}

- (void) setMultipointEnabled: (BOOL)enable
{
if (enable != self.multipointEnabled)
{
//If no multipoint pitch or size have been specified yet,
//inherit them now from the fixed-point pitch and font size.
if (enable)
{
if (_multipointFontPitch == 0)
_multipointFontPitch = (CGFloat)self.fontPitch;

if (_multipointFontSize == 0)
self.multipointFontSize = BXESCPBaseFontSize;

self.characterAdvance = BXCharacterAdvanceAuto;
}

_multipointEnabled = enable;
_textAttributesNeedUpdate = YES;
}
}

- (void) setLetterSpacing: (double)spacing
{
_letterSpacing = spacing;
Expand Down Expand Up @@ -482,8 +509,9 @@ - (void) _updateTextAttributes
NSSize fontSize;
if (self.multipointEnabled)
{
fontSize = NSMakeSize(_multipointFontSize, _multipointFontSize);
_effectivePitch = _multipointFontPitch;
fontSize = NSMakeSize(self.multipointFontSize, self.multipointFontSize);
_effectivePitch = self.multipointFontPitch;
//TODO: apply width scaling to characters based on pitch?
}
else
{
Expand Down Expand Up @@ -511,10 +539,21 @@ - (void) _updateTextAttributes
}

fontSize.width *= (BXFontPitch10CPI / _effectivePitch);

//Apply double-width and double-height printing if desired
if (self.doubleWidth || self.doubleWidthForLine)
{
fontSize.width *= 2.0;
_effectivePitch *= 0.5;
}
if (self.doubleHeight)
{
fontSize.height *= 2.0;
}
}

//Shrink superscripted and subscripted characters to 2/3rds their normal size,
//unless we're at a particularly small font size.
//unless we're below the 8pt font-size threshold.
if ((self.superscript || self.subscript) && fontSize.height > 8.0)
{
double subscriptScale = 2.0/3.0;
Expand Down Expand Up @@ -834,6 +873,11 @@ - (void) reset
[self.delegate printerDidInitialize: self];
}

- (double) characterWidth
{
return 1 / (double)self.fontPitch;
}

- (double) effectiveCharacterWidth
{
//Recalculate the text attributes in case the effective pitch has changed
Expand All @@ -851,11 +895,15 @@ - (double) characterAdvance
return self.effectiveCharacterWidth;
}

- (double) characterWidth
- (double) effectiveLetterSpacing
{
return 1 / (double)self.fontPitch;
if (self.doubleWidth || self.doubleWidthForLine)
return self.letterSpacing * 2;
else
return self.letterSpacing;
}


- (void) _startNewLine
{
_headPosition.x = _leftMargin;
Expand Down Expand Up @@ -1144,7 +1192,9 @@ - (void) _printCharacter: (uint8_t)character
//Construct a string for drawing the glyph and work out how big it will be rendered.
NSString *stringToPrint = [NSString stringWithCharacters: &codepoint length: 1];
NSSize stringSize = [stringToPrint sizeWithAttributes: self.textAttributes];
double stringWidth = (stringSize.width / 72.0);

double stringWidth = stringSize.width / 72.0;
double descenderHeight = [[self.textAttributes objectForKey: NSFontAttributeName] descender] / 72.0;

//If we're printing in fixed-width, work out how big a space the string should fill
double advance = 0;
Expand All @@ -1157,21 +1207,22 @@ - (void) _printCharacter: (uint8_t)character
advance = self.effectiveCharacterWidth;
}

//Draw the glyph at the current position ofƒ the print head,
//Draw the glyph at the current position off the print head,
//centered within the space it is expected to occupy.
NSPoint textOrigin = self.headPosition;

//Note that the head position is positioned at the visual top left of the line to print,
//but ESC/P printers print text 20/180 inch below this point, regardless of the current font size.
//This ensures that baselines always line up regardless of font size.
//The virtual head position is positioned at the top of the line to print,
//but ESC/P printers print text on a baseline that's 20/180 inch below this point
//(regardless of the current font size.) This ensures that baselines always line
//up regardless of font size.
//(Also note that we have to take the descender height into consideration because
//AppKit's drawAtPoint: function draws from the bottom of the descender, not the baseline.)
textOrigin.y += BXESCPBaselineOffset - descenderHeight;

NSPoint textOrigin = self.headPosition;
textOrigin.y += BXESCPBaselineOffset;
//Position the glyph in the middle of the expected character width.
//This prevents characters in proportional-but-monospaced fonts bunching up together.
textOrigin.x += (advance - stringWidth) * 0.5;

//When in fixed-width mode, position the glyph smack in the middle of the expected advance.
if (!self.proportional)
{
textOrigin.x += (advance - stringWidth) * 0.5;
}

NSPoint drawPos = [self convertPointFromPage: textOrigin];

Expand All @@ -1187,8 +1238,6 @@ - (void) _printCharacter: (uint8_t)character
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext: context];

//Note that drawAtPoint:withAttributes will draw the string with the baseline
//positioned at the specified offset.
[stringToPrint drawAtPoint: drawPos
withAttributes: self.textAttributes];

Expand All @@ -1201,8 +1250,8 @@ - (void) _printCharacter: (uint8_t)character
[NSGraphicsContext restoreGraphicsState];
}

//Advance the head past the string
_headPosition.x += advance + self.letterSpacing;
//Advance the head past the string.
_headPosition.x += advance + self.effectiveLetterSpacing;

//Wrap the line if the character after this one would go over the right margin.
//(This may also trigger a new page.)
Expand Down Expand Up @@ -1448,7 +1497,8 @@ - (void) _parseESCPCommandParameter: (uint8_t)param
//Collect a stream of horizontal tab positions.
else if (_currentESCPCommand == 'D')
{
//Horizontal tab positions are specified as number of characters from left margin; convert this to a width in inches.
//Horizontal tab positions are specified as number of characters from left margin:
//convert this to a width in inches using the current character width as a guide.
double tabPos = param * self.characterWidth;

//Once we get a null sentinel or a tab position that's lower than the previous position,
Expand Down Expand Up @@ -1793,40 +1843,33 @@ - (void) _executeESCCommand: (uint16_t)command parameters: (uint8_t *)params
break;

case 'W': // Turn double-width printing on/off (ESC W)
if (!_multipointEnabled)
if (!self.multipointEnabled)
{
self.doubleWidth = (params[0] == '1' || params[0] == 1);
self.doubleWidthForLine = NO;
}
break;
case 'X': // Select font by pitch and point (ESC X)
{
_multipointEnabled = YES;

//Copy current non-multipoint CPI if no value was set so far
if (_multipointFontPitch == 0)
_multipointFontPitch = (double)self.fontPitch;
self.multipointEnabled = YES;

double pitch = params[0];
//Font size is specified as a double-byte parameter
double fontSize = WIDEPARAM(params, 1);

if (pitch == 1) // Proportional spacing
if (pitch == 1) //Activate proportional spacing
{
self.proportional = YES;
}
else if (pitch >= 5)
else if (pitch >= 5) //Set the font pitch in 360ths of an inch
{
_multipointFontPitch = 360.0 / pitch;
self.multipointFontPitch = 360.0 / pitch;
}

//Font size is specified as a double-byte parameter
if (fontSize > 0) // Set points
_multipointFontSize = fontSize / 2.0;
//Fall back on a default point size of 10.5
else if (_multipointFontSize == 0)
_multipointFontSize = BXESCPBaseFontSize;

_textAttributesNeedUpdate = YES;
if (fontSize > 0) //Set point size
{
self.multipointFontSize = fontSize / 2.0;
}
}
break;

Expand Down Expand Up @@ -1943,7 +1986,7 @@ - (void) _executeESCCommand: (uint16_t)command parameters: (uint8_t *)params
break;

case 'w': // Turn double-height printing on/off (ESC w)
if (!_multipointEnabled)
if (!self.multipointEnabled)
{
self.doubleHeight = (params[0] == '1' || params[0] == 1);
}
Expand Down Expand Up @@ -2102,7 +2145,8 @@ - (BOOL) _parseControlCharacter: (uint8_t)character

case '\b': // Backspace (BS)
{
double newX = _headPosition.x - self.characterAdvance;
double space = self.characterAdvance + self.effectiveLetterSpacing;
double newX = _headPosition.x - space;
if (newX >= _leftMargin)
_headPosition.x = newX;
}
Expand Down

0 comments on commit d5a2757

Please sign in to comment.