アットウィキロゴ

CoreTextArcCocoa

CoreTextArcCocoa


Rubyに置き換えながら内容を理解する

 def draw_rect(rect)
   return if (@font.nil? or @string.nil?)
   # コンテキスト初期化
   context = NSGraphicsContext.current_context.graphics_port
   context.set_text_matrix CGAffineTransform::Identity
   # 背景色と背景塗り
   NSColor.whitecolor.set
   rect.fill
   # 文字列と行検査
   line = CTLine::CreateWithAttributedString(@attributed_string)
   glyph_count = line.get_glyph_count
   return if glyph_count.zero?
   
   # グリフ弧情報
   glyph_arc_info = []
   prepare_glyph_arc_info(line, glyph_count, glyph_arc_info)
   
   # 原点をビューの左下から、ビューのセンター付近へ
   # コンテキストの状態を保存(あとでリストアする)
   context.save_g_state
   context.translate_CTM(rect.to_CGRect.get_mid_x, rect.to_CGRect.get_mid_y -@radius / 2.0) 
   # 検査用の赤い弧を引っ張る
   context.
     begin_path.
     context_add_arc(0.0, 0.0, @radius, Math::PI, 0.0, 1).
     set_RGB_stroke_color(1.0, 0.0, 0.0, 1.0).
     stroke_path
   context.rotate_CTM(Math::PI_2)# コンテキストを反時計回りに90度回す
   text_position = CGPoint.new(0.0, @radius)
   # これから実際に描画していく。直前のグリフとそれぞれのグリフの角度の埋め合わせは計算済み
   # 
   # 半円状のパスに沿ってグリフが広がります
   context.set_text_position(text_position.x, text_position.y)
   run_array = line.get_glyph_runs
   run_count = run_array.count
   # 
   glyph_offset = 0
   run_array.each_with_index{|run, run_index|
     run_glyph_count = run.count
     draw_substituted_glyphs_manualy = true
     run_font = run.get_attributes[kCTFontAttributeName]
     if @dims_substituted_glyphs && !(@font == run_font) then
       draw_substituted_glyphs_manualy = true
     end
     run_glyph_index = 0
     glyph_arc_info.each_with_index{|info, run_glyph_index|
       glyph_range = CFRange.new(idx, 1)
       context.rotate_CTM -info.angle
       glyph_width = info.width
       half_glyph_width = glyph_width / 2.0
       position_for_this_glyph = CGPoint.new(text_position.x - half_glyph_width, text_position.y)
       text_position.x -= glyph_width
       
       text_matrix = run.get_text_matrix
       text_matrix.tx = position_for_this_glyph.x
       text_matrix.ty = position_for_this_glyph.y
       context.set_text_matrix text_matrix
       
       if (!draw_substituted_glyphs_manually) then
         run.draw(context, glyph_range) 
       else 
         cg_font = run_font.copy_graphics_font(nil)
         glyph = run.get_glyph(glyph_range)
         position = run.get_positions(glyph_range)
         
         context.set_font(cg_font)
         context.set_font_size(run_font.get_size)
         context.set_RGB_fill_color(0.25, 0.25, 0.25, 0.5)
         context.show_glyphs_at_positions(glyph, position, 1)
       end
       
       # グリフ外接枠の表示(青枠)
       if @shows_glyph_bounds.nonzero? then
         glyph_bounds = run.get_image_bounds(context, glyph_range)
         context.set_RGB_stroke_color(0.0, 0.0, 1.0, 1.0)
         context.stroke_rect(glyph_bounds)
       end
       
       # 行メトリクスによって定義された境界線の表示
       if @show_line_metrics.nonzero? then
         [ascent, descent] = run.get_typographic_bounds(nil)
         line_metrics = CGRect.new(-half_glyph_width, position_for_this_glyph.y - descent,
           glyph_width, ascent+descent)
         context.set_RGB_stroke_color(0.0, 1.0, 0.0, 1.0)
         context.stroke_rect(line_metrics)
       end
     }
     glyph_offset += run_glyph_count
   }
   
   context.restore_g_state
   glyph_arc_info.free
   line.release
 end

 - (void)drawRect:(NSRect)rect {
// Don't draw if we don't have a font or string
// フォントや文字列が無い場合は、即リターン
if (self.font == NULL || self.string == NULL) 
	return;
       
// Initialize the text matrix to a known value
// テキストマトリックスをKnownValueに対して初期化する
CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
CGContextSetTextMatrix(context, CGAffineTransformIdentity);

// Draw a white background
// 背景を白で描画
[[NSColor whiteColor] set];
NSRectFill(rect);

CTLineRef line = CTLineCreateWithAttributedString((CFAttributedStringRef)self.attributedString);
assert(line != NULL);

CFIndex glyphCount = CTLineGetGlyphCount(line);
if (glyphCount == 0) {
	CFRelease(line);
	return;
}

GlyphArcInfo *	glyphArcInfo = (GlyphArcInfo*)calloc(glyphCount, sizeof(GlyphArcInfo));
PrepareGlyphArcInfo(line, glyphCount, glyphArcInfo);

// Move the origin from the lower left of the view nearer to its center.
CGContextSaveGState(context);
CGContextTranslateCTM(context, CGRectGetMidX(NSRectToCGRect(rect)), CGRectGetMidY(NSRectToCGRect(rect)) - self.radius / 2.0);

// Stroke the arc in red for verification.
CGContextBeginPath(context);
CGContextAddArc(context, 0.0, 0.0, self.radius, M_PI, 0.0, 1);
CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);
CGContextStrokePath(context);

// Rotate the context 90 degrees counterclockwise.
CGContextRotateCTM(context, M_PI_2);

// Now for the actual drawing. The angle offset for each glyph relative to the previous glyph has already been calculated; with that information in hand, draw those glyphs overstruck and centered over one another, making sure to rotate the context after each glyph so the glyphs are spread along a semicircular path.
CGPoint textPosition = CGPointMake(0.0, self.radius);
CGContextSetTextPosition(context, textPosition.x-61.2, textPosition.y);

CFArrayRef runArray = CTLineGetGlyphRuns(line);
CFIndex runCount = CFArrayGetCount(runArray);

CFIndex glyphOffset = 0;
CFIndex runIndex = 0;
for (; runIndex < runCount; runIndex++) {
	CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runArray, runIndex);
	CFIndex runGlyphCount = CTRunGetGlyphCount(run);
	Boolean	drawSubstitutedGlyphsManually = false;
	CTFontRef runFont = CFDictionaryGetValue(CTRunGetAttributes(run), kCTFontAttributeName);
	
	// Determine if we need to draw substituted glyphs manually. Do so if the runFont is not the same as the overall font.
	if (self.dimsSubstitutedGlyphs && ![self.font isEqual:(NSFont *)runFont]) {
		drawSubstitutedGlyphsManually = true;
	}
	
	CFIndex runGlyphIndex = 0;
	for (; runGlyphIndex < runGlyphCount; runGlyphIndex++) {
		CFRange glyphRange = CFRangeMake(runGlyphIndex, 1);
		CGContextRotateCTM(context, -(glyphArcInfo[runGlyphIndex + glyphOffset].angle));
		
		// Center this glyph by moving left by half its width.
		CGFloat glyphWidth = glyphArcInfo[runGlyphIndex + glyphOffset].width;
		CGFloat halfGlyphWidth = glyphWidth / 2.0;
		CGPoint positionForThisGlyph = CGPointMake(textPosition.x - halfGlyphWidth, textPosition.y);
		
		// Glyphs are positioned relative to the text position for the line, so offset text position leftwards by this glyph's width in preparation for the next glyph.
		textPosition.x -= glyphWidth;
		
		CGAffineTransform textMatrix = CTRunGetTextMatrix(run);
		textMatrix.tx = positionForThisGlyph.x;
		textMatrix.ty = positionForThisGlyph.y;
		CGContextSetTextMatrix(context, textMatrix);
		
		if (!drawSubstitutedGlyphsManually) {
			CTRunDraw(run, context, glyphRange);
		} 
		else {
			// We need to draw the glyphs manually in this case because we are effectively applying a graphics operation by setting the context fill color. Normally we would use kCTForegroundColorAttributeName, but this does not apply as we don't know the ranges for the colors in advance, and we wanted demonstrate how to manually draw.
			CGFontRef cgFont = CTFontCopyGraphicsFont(runFont, NULL);
			CGGlyph glyph;
			CGPoint position;
			
			CTRunGetGlyphs(run, glyphRange, &glyph);
			CTRunGetPositions(run, glyphRange, &position);
			
			CGContextSetFont(context, cgFont);
			CGContextSetFontSize(context, CTFontGetSize(runFont));
			CGContextSetRGBFillColor(context, 0.25, 0.25, 0.25, 0.5);
			CGContextShowGlyphsAtPositions(context, &glyph, &position, 1);
			
			CFRelease(cgFont);
		}
		
		// Draw the glyph bounds グリフ外接枠の表示(青)
		if ((self.showsGlyphBounds) != 0) {
			CGRect glyphBounds = CTRunGetImageBounds(run, context, glyphRange);
			
			CGContextSetRGBStrokeColor(context, 0.0, 0.0, 1.0, 1.0);// 青
			CGContextStrokeRect(context, glyphBounds);
		}
		// Draw the bounding boxes defined by the line metrics() 行の
		if ((self.showsLineMetrics) != 0) {
			CGRect lineMetrics;
			CGFloat ascent, descent;
			
			CTRunGetTypographicBounds(run, glyphRange, &ascent, &descent, NULL);
			
			// The glyph is centered around the y-axis
			lineMetrics.origin.x = -halfGlyphWidth;
			lineMetrics.origin.y = positionForThisGlyph.y - descent;
			lineMetrics.size.width = glyphWidth; 
			lineMetrics.size.height = ascent + descent;
			
			CGContextSetRGBStrokeColor(context, 0.0, 1.0, 0.0, 1.0);// 緑
			CGContextStrokeRect(context, lineMetrics);
		}
	}
	
	glyphOffset += runGlyphCount;
}

CGContextRestoreGState(context);

free(glyphArcInfo);
CFRelease(line);	
 }

タグ:

+ タグ編集
  • タグ:
最終更新:2010年06月14日 17:05
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。