static VALUE layout_iter_get_line_yrange(VALUE self) { int y0, y1; pango_layout_iter_get_line_yrange(_SELF(self), &y0, &y1); return rb_assoc_new(INT2NUM(y0), INT2NUM(y1)); }
void gnm_rendered_value_remeasure (GnmRenderedValue *rv) { if (rv->rotation) { GnmRenderedRotatedValue *rrv = (GnmRenderedRotatedValue *)rv; PangoContext *context = pango_layout_get_context (rv->layout); double sin_a, abs_sin_a, cos_a; int sdx = 0; int x0 = 0, x1 = 0; PangoLayoutIter *iter; int l = 0; int lwidth; sin_a = rrv->rotmat.xy; abs_sin_a = fabs (sin_a); cos_a = rrv->rotmat.xx; pango_context_set_matrix (context, &rrv->rotmat); pango_layout_context_changed (rv->layout); rrv->linecount = pango_layout_get_line_count (rv->layout); rrv->lines = g_new (struct GnmRenderedRotatedValueInfo, rrv->linecount); pango_layout_get_size (rv->layout, &lwidth, NULL); rv->layout_natural_height = 0; iter = pango_layout_get_iter (rv->layout); do { PangoRectangle logical; int x, dx, dy, indent; int h, ytop, ybot, baseline; pango_layout_iter_get_line_extents (iter, NULL, &logical); pango_layout_iter_get_line_yrange (iter, &ytop, &ybot); baseline = pango_layout_iter_get_baseline (iter); indent = logical.x; if (sin_a < 0) indent -= lwidth; if (l == 0 && rv->noborders) sdx = (int)(baseline * sin_a - ybot / sin_a); dx = sdx + (int)(ybot / sin_a + indent * cos_a); dy = (int)((baseline - ybot) * cos_a - indent * sin_a); rrv->lines[l].dx = dx; rrv->lines[l].dy = dy; /* Left edge. */ x = dx - (int)((baseline - ytop) * sin_a); x0 = MIN (x0, x); /* Right edge. */ x = dx + (int)(logical.width * cos_a + (ybot - baseline) * sin_a); x1 = MAX (x1, x); h = logical.width * abs_sin_a + logical.height * cos_a; if (h > rv->layout_natural_height) rv->layout_natural_height = h; l++; } while (pango_layout_iter_next_line (iter)); pango_layout_iter_free (iter); rv->layout_natural_width = x1 - x0; if (sin_a < 0) { int dx = rv->layout_natural_width; for (l = 0; l < rrv->linecount; l++) rrv->lines[l].dx += dx; } for (l = 0; l < rrv->linecount; l++) rrv->lines[l].dy += rv->layout_natural_height; #if 0 g_print ("Natural size: %d x %d\n", rv->layout_natural_width, rv->layout_natural_height); #endif pango_context_set_matrix (context, NULL); pango_layout_context_changed (rv->layout); } else
/* split a text buffer into chunks using the passed Pango layout */ GList * split_for_layout(PangoLayout * layout, const gchar * text, PangoAttrList * attributes, BalsaPrintSetup * psetup, gboolean is_header, GArray ** offsets) { GList *split_list = NULL; PangoLayoutIter *iter; const gchar *start; gint p_offset; gboolean add_tab; gint p_y0; gint p_y1; gint p_y_pos; gint p_height; /* set the text and its attributes, then get an iter */ pango_layout_set_text(layout, text, -1); if (attributes) pango_layout_set_attributes(layout, attributes); if (offsets) *offsets = g_array_new(FALSE, FALSE, sizeof(guint)); iter = pango_layout_get_iter(layout); /* loop over lines */ start = text; p_offset = 0; add_tab = FALSE; p_y_pos = C_TO_P(psetup->c_y_pos); p_height = C_TO_P(psetup->c_height); do { pango_layout_iter_get_line_yrange(iter, &p_y0, &p_y1); if (p_y_pos + p_y1 - p_offset > p_height) { gint index; gint tr; gchar *chunk; gboolean ends_with_nl; if (offsets) { guint offs = start - text; *offsets = g_array_append_val(*offsets, offs); } pango_layout_xy_to_index(layout, 0, p_y0, &index, &tr); ends_with_nl = text[index - 1] == '\n'; if (ends_with_nl) index--; chunk = g_strndup(start, text + index - start); if (add_tab) split_list = g_list_append(split_list, g_strconcat("\t", chunk, NULL)); else split_list = g_list_append(split_list, g_strdup(chunk)); add_tab = is_header && !ends_with_nl; g_free(chunk); start = text + index; if (ends_with_nl) start++; if (*start == '\0') p_y_pos = p_height; else { p_y_pos = 0; psetup->page_count++; } p_offset = p_y0; } } while (pango_layout_iter_next_line(iter)); pango_layout_iter_free(iter); /* append any remaining stuff */ if (*start != '\0') { p_y_pos += p_y1 - p_offset; if (offsets) { guint offs = start - text; *offsets = g_array_append_val(*offsets, offs); } if (add_tab) split_list = g_list_append(split_list, g_strconcat("\t", start, NULL)); else split_list = g_list_append(split_list, g_strdup(start)); } /* remember the new y position in cairo units */ psetup->c_y_pos = P_TO_C(p_y_pos); /* return the list */ return split_list; }
GpStatus pango_MeasureString (GpGraphics *graphics, GDIPCONST WCHAR *stringUnicode, int length, GDIPCONST GpFont *font, GDIPCONST RectF *rc, GDIPCONST GpStringFormat *format, RectF *boundingBox, int *codepointsFitted, int *linesFilled) { PangoLayout *layout; PangoLayoutLine *line; PangoRectangle logical; PangoLayoutIter *iter; int *charsRemoved = NULL; cairo_save (graphics->ct); layout = gdip_pango_setup_layout (graphics, stringUnicode, length, font, rc, boundingBox, format, &charsRemoved); if (!layout) { cairo_restore (graphics->ct); return OutOfMemory; } if (codepointsFitted) { int charsFitted; int lastIndex; int y0; int y1; double min_x; double max_x; double max_y; const char *layoutText; if (boundingBox && format && (format->formatFlags & StringFormatFlagsDirectionVertical)) { min_x = boundingBox->Y; max_x = boundingBox->Y + boundingBox->Height; max_y = boundingBox->X + boundingBox->Width; } else if (boundingBox) { min_x = boundingBox->X; max_x = boundingBox->X + boundingBox->Width; max_y = boundingBox->Y + boundingBox->Height; } else if (format && (format->formatFlags & StringFormatFlagsDirectionVertical)) { min_x = rc->Y; max_x = rc->Y + rc->Height; max_y = rc->X + rc->Width; } else { min_x = rc->X; max_x = rc->X + rc->Width; max_y = rc->Y + rc->Height; } lastIndex = 0; iter = pango_layout_get_iter (layout); do { if (iter == NULL) break; pango_layout_iter_get_line_yrange (iter, &y0, &y1); if (y0 / PANGO_SCALE >= max_y) break; if (pango_layout_iter_at_last_line (iter)) { do { pango_layout_iter_get_char_extents (iter, &logical); /* check both max and min to catch right-to-left text, also width may be negative */ if ((logical.x / PANGO_SCALE > max_x || (logical.x + logical.width) / PANGO_SCALE > max_x) || (logical.x / PANGO_SCALE < min_x || (logical.x + logical.width) / PANGO_SCALE < min_x)) break; lastIndex = pango_layout_iter_get_index (iter); } while (pango_layout_iter_next_char (iter)); break; } else { line = pango_layout_iter_get_line_readonly (iter); lastIndex = line->start_index + line->length - 1; } } while (pango_layout_iter_next_line (iter)); pango_layout_iter_free (iter); layoutText = pango_layout_get_text (layout); /* this can happen when the string ends in a newline */ if (lastIndex >= strlen (layoutText)) lastIndex = strlen (layoutText) - 1; /* Add back in any & characters removed and the final newline characters (if any) */ charsFitted = g_utf8_strlen (layoutText, lastIndex + 1) + charsRemoved [lastIndex]; //g_warning("lastIndex: %d\t\tcharsRemoved: %d", lastIndex, charsRemoved[lastIndex]); /* safe because of null termination */ switch (layoutText [lastIndex + 1]) { case '\r': charsFitted++; if (layoutText [lastIndex + 2] == '\n') charsFitted++; break; case '\n': charsFitted++; break; } *codepointsFitted = charsFitted; } GdipFree (charsRemoved); if (linesFilled) { *linesFilled = pango_layout_get_line_count (layout); // g_warning ("linesFilled %d", *linesFilled); } // else g_warning ("linesFilled %d", pango_layout_get_line_count (layout)); g_object_unref (layout); cairo_restore (graphics->ct); return Ok; }
PangoLayout* gdip_pango_setup_layout (GpGraphics *graphics, GDIPCONST WCHAR *stringUnicode, int length, GDIPCONST GpFont *font, GDIPCONST RectF *rc, RectF *box, GDIPCONST GpStringFormat *format, int **charsRemoved) { GpStringFormat *fmt; PangoLayout *layout; PangoContext *context; PangoRectangle logical; /* logical size of text (used for alignment) */ PangoRectangle ink; /* ink size of text (to pixel boundaries) */ PangoAttrList *list = NULL; GString *ftext; PangoTabArray *tabs; PangoLayoutIter *iter; int i; int FrameWidth; /* rc->Width (or rc->Height if vertical) */ int FrameHeight; /* rc->Height (or rc->Width if vertical) */ int FrameX; /* rc->X (or rc->Y if vertical) */ int FrameY; /* rc->Y (or rc->X if vertical) */ int y0; /* y0,y1,clipNN used for checking line positions vs. clip rectangle */ int y1; double clipx1; double clipx2; double clipy1; double clipy2; int trimSpace; /* whether or not to trim the space */ gchar *text = ucs2_to_utf8 (stringUnicode, length); if (!text) return NULL; length = strlen(text); if (charsRemoved) { (*charsRemoved) = GdipAlloc (sizeof (int) * length); if (!*charsRemoved) { GdipFree (text); return NULL; } memset (*charsRemoved, 0, sizeof (int) * length); } /* TODO - Digit substitution */ // g_warning ("layout >%s< (%d) [x %g, y %g, w %g, h %g] [font %s, %g points]", text, length, rc->X, rc->Y, rc->Width, FrameHeight, font->face, font->emSize); /* a NULL format is valid, it means get the generic default values (and free them later) */ if (!format) { GpStatus status = GdipStringFormatGetGenericDefault ((GpStringFormat **)&fmt); if (status != Ok) { GdipFree (text); return NULL; } } else { fmt = (GpStringFormat *)format; } layout = pango_cairo_create_layout (graphics->ct); /* context is owned by Pango (i.e. not referenced counted) do not free */ context = pango_layout_get_context (layout); pango_layout_set_font_description (layout, gdip_get_pango_font_description ((GpFont*) font)); if (fmt->formatFlags & StringFormatFlagsDirectionVertical) { FrameWidth = MAKE_SAFE_FOR_PANGO (SAFE_FLOAT_TO_UINT32 (rc->Height)); FrameHeight = MAKE_SAFE_FOR_PANGO (SAFE_FLOAT_TO_UINT32 (rc->Width)); FrameX = SAFE_FLOAT_TO_UINT32 (rc->Y); FrameY = SAFE_FLOAT_TO_UINT32 (rc->X); } else { FrameWidth = MAKE_SAFE_FOR_PANGO (SAFE_FLOAT_TO_UINT32 (rc->Width)); FrameHeight = MAKE_SAFE_FOR_PANGO (SAFE_FLOAT_TO_UINT32 (rc->Height)); FrameX = SAFE_FLOAT_TO_UINT32 (rc->X); FrameY = SAFE_FLOAT_TO_UINT32 (rc->Y); } //g_warning("FW: %d\tFH: %d", FrameWidth, FrameHeight); if ((FrameWidth <= 0) || (fmt->formatFlags & StringFormatFlagsNoWrap)) { pango_layout_set_width (layout, -1); //g_warning ("Setting width: %d", -1); } else { pango_layout_set_width (layout, FrameWidth * PANGO_SCALE); //g_warning ("Setting width: %d", FrameWidth * PANGO_SCALE); } if ((rc->Width != 0) && (rc->Height != 0) && ((fmt->formatFlags & StringFormatFlagsNoClip) == 0)) { // g_warning ("\tclip [%g %g %g %g]", rc->X, rc->Y, rc->Width, rc->Height); /* We do not call cairo_reset_clip because we want to take previous clipping into account */ /* Use rc instead of frame variables because this is pre-transform */ gdip_cairo_rectangle (graphics, rc->X, rc->Y, rc->Width, rc->Height, TRUE); cairo_clip (graphics->ct); } /* with GDI+ the API not the renderer makes the direction decision */ pango_layout_set_auto_dir (layout, FALSE); if (!(fmt->formatFlags & StringFormatFlagsDirectionRightToLeft) != !(fmt->formatFlags & StringFormatFlagsDirectionVertical)) { pango_context_set_base_dir (context, PANGO_DIRECTION_WEAK_RTL); pango_layout_context_changed (layout); /* horizontal alignment */ switch (fmt->alignment) { case StringAlignmentNear: pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT); break; case StringAlignmentCenter: pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); break; case StringAlignmentFar: pango_layout_set_alignment (layout, PANGO_ALIGN_LEFT); break; } } else { /* pango default base dir is WEAK_LTR, which is what we want */ /* horizontal alignment */ switch (fmt->alignment) { case StringAlignmentNear: pango_layout_set_alignment (layout, PANGO_ALIGN_LEFT); break; case StringAlignmentCenter: pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); break; case StringAlignmentFar: pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT); break; } } #ifdef PANGO_VERSION_CHECK #if PANGO_VERSION_CHECK(1,16,0) if (fmt->formatFlags & StringFormatFlagsDirectionVertical) { if (fmt->formatFlags & StringFormatFlagsDirectionRightToLeft) { cairo_rotate (graphics->ct, M_PI/2.0); cairo_translate (graphics->ct, 0, -FrameHeight); pango_cairo_update_context (graphics->ct, context); } else { cairo_rotate (graphics->ct, 3.0*M_PI/2.0); cairo_translate (graphics->ct, -FrameWidth, 0); pango_cairo_update_context (graphics->ct, context); } /* only since Pango 1.16 */ pango_context_set_base_gravity (context, PANGO_GRAVITY_AUTO); pango_context_set_gravity_hint (context, PANGO_GRAVITY_HINT_LINE); pango_layout_context_changed (layout); } #endif #endif /* TODO - StringFormatFlagsDisplayFormatControl scan and replace them ??? */ /* Trimming options seem to apply only to the end of the string - gdi+ will still wrap * with preference to word first, then character. Unfortunately, pango doesn't have * any way to differentiate wrapping behavior from trimming behavior that I could find */ pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR); switch (fmt->trimming) { case StringTrimmingNone: pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_NONE); break; case StringTrimmingCharacter: pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_NONE); break; case StringTrimmingWord: pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_NONE); break; case StringTrimmingEllipsisCharacter: pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END); if (!(fmt->formatFlags & StringFormatFlagsNoWrap)) pango_layout_set_height (layout, FrameHeight == 0 ? G_MAXINT32 : FrameHeight * PANGO_SCALE); break; case StringTrimmingEllipsisWord: pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END); if (!(fmt->formatFlags & StringFormatFlagsNoWrap)) pango_layout_set_height (layout, FrameHeight == 0 ? G_MAXINT32 : FrameHeight * PANGO_SCALE); break; case StringTrimmingEllipsisPath: pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_MIDDLE); if (!(fmt->formatFlags & StringFormatFlagsNoWrap)) pango_layout_set_height (layout, FrameHeight == 0 ? G_MAXINT32 : FrameHeight * PANGO_SCALE); break; } /* some stuff can only be done by manipulating the attributes (but we can avoid this most of the time) */ if ((fmt->formatFlags & StringFormatFlagsNoFontFallback) || (font->style & (FontStyleUnderline | FontStyleStrikeout))) { list = gdip_get_layout_attributes (layout); /* StringFormatFlagsNoFontFallback */ if (fmt->formatFlags & StringFormatFlagsNoFontFallback) { PangoAttribute *attr = pango_attr_fallback_new (FALSE); attr->start_index = 0; attr->end_index = length; pango_attr_list_insert (list, attr); } if (font->style & FontStyleUnderline) { PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE); attr->start_index = 0; attr->end_index = length; pango_attr_list_insert (list, attr); } if (font->style & FontStyleStrikeout) { PangoAttribute *attr = pango_attr_strikethrough_new (TRUE); attr->start_index = 0; attr->end_index = length; pango_attr_list_insert (list, attr); } } if (fmt->numtabStops > 0) { float tabPosition; tabs = pango_tab_array_new (fmt->numtabStops, FALSE); tabPosition = fmt->firstTabOffset; for (i = 0; i < fmt->numtabStops; i++) { tabPosition += fmt->tabStops[i]; pango_tab_array_set_tab (tabs, i, PANGO_TAB_LEFT, (gint)min (tabPosition, PANGO_MAX) * PANGO_SCALE); } pango_layout_set_tabs (layout, tabs); pango_tab_array_free (tabs); } //g_warning ("length before ws removal: %d", length); trimSpace = (fmt->formatFlags & StringFormatFlagsMeasureTrailingSpaces) == 0; switch (fmt->hotkeyPrefix) { case HotkeyPrefixHide: /* we need to remove any accelerator from the string */ ftext = gdip_process_string (text, length, 1, trimSpace, NULL, charsRemoved); break; case HotkeyPrefixShow: /* optimization: is seems that we never see the hotkey when using an underline font */ if (font->style & FontStyleUnderline) { /* so don't bother drawing it (and simply add the '&' character) */ ftext = gdip_process_string (text, length, 1, trimSpace, NULL, charsRemoved); } else { /* find accelerator and add attribute to the next character (unless it's the prefix too) */ if (!list) list = gdip_get_layout_attributes (layout); ftext = gdip_process_string (text, length, 1, trimSpace, list, charsRemoved); } break; default: ftext = gdip_process_string (text, length, 0, trimSpace, NULL, charsRemoved); break; } length = ftext->len; //g_warning ("length after ws removal: %d", length); if (list) { pango_layout_set_attributes (layout, list); pango_attr_list_unref (list); } // g_warning("\tftext>%s< (%d)", ftext->str, -1); pango_layout_set_text (layout, ftext->str, ftext->len); GdipFree (text); g_string_free(ftext, TRUE); /* Trim the text after the last line for ease of counting lines/characters */ /* Also prevents drawing whole lines outside the boundaries if NoClip was specified */ /* In case of pre-existing clipping, use smaller of clip rectangle or our specified height */ if (FrameHeight > 0) { cairo_clip_extents (graphics->ct, &clipx1, &clipy1, &clipx2, &clipy2); if (clipy2 > 0 && !(fmt->formatFlags & StringFormatFlagsNoClip)) clipy2 = min (clipy2, FrameHeight + FrameY); else clipy2 = FrameHeight + FrameY; iter = pango_layout_get_iter (layout); do { if (iter == NULL) break; pango_layout_iter_get_line_yrange (iter, &y0, &y1); //g_warning("yrange: %d %d clipy2: %f", y0 / PANGO_SCALE, y1 / PANGO_SCALE, clipy2); /* StringFormatFlagsLineLimit */ if (((fmt->formatFlags & StringFormatFlagsLineLimit) && y1 / PANGO_SCALE > clipy2) || (y0 / PANGO_SCALE > clipy2)) { PangoLayoutLine *line = pango_layout_iter_get_line_readonly (iter); pango_layout_set_text (layout, pango_layout_get_text (layout), line->start_index); break; } } while (pango_layout_iter_next_line (iter)); pango_layout_iter_free (iter); } pango_layout_get_pixel_extents (layout, &ink, &logical); // g_warning ("\tlogical\t[x %d, y %d, w %d, h %d][x %d, y %d, w %d, h %d]", logical.x, logical.y, logical.width, logical.height, ink.x, ink.y, ink.width, ink.height); if ((fmt->formatFlags & StringFormatFlagsNoFitBlackBox) == 0) { /* By default don't allow overhang - ink space may be larger than logical space */ if (fmt->formatFlags & StringFormatFlagsDirectionVertical) { box->X = min (ink.y, logical.y); box->Y = min (ink.x, logical.x); box->Height = max (ink.width, logical.width); box->Width = max (ink.height, logical.height); } else { box->X = min (ink.x, logical.x); box->Y = min (ink.y, logical.y); box->Height = max (ink.height, logical.height); box->Width = max (ink.width, logical.width); } } else { /* Allow overhang */ if (fmt->formatFlags & StringFormatFlagsDirectionVertical) { box->X = logical.y; box->Y = logical.x; box->Height = logical.width; box->Width = logical.height; } else { box->X = logical.x; box->Y = logical.y; box->Height = logical.height; box->Width = logical.width; } } // g_warning ("\tbox\t[x %g, y %g, w %g, h %g]", box->X, box->Y, box->Width, box->Height); /* vertical alignment*/ if (fmt->formatFlags & StringFormatFlagsDirectionVertical) { switch (fmt->lineAlignment) { case StringAlignmentNear: break; case StringAlignmentCenter: box->X += (rc->Width - box->Width) / 2; break; case StringAlignmentFar: box->X += (rc->Width - box->Width); break; } } else { switch (fmt->lineAlignment) { case StringAlignmentNear: break; case StringAlignmentCenter: box->Y += (rc->Height - box->Height) / 2; break; case StringAlignmentFar: box->Y += (rc->Height - box->Height); break; } } // g_warning ("va-box\t[x %g, y %g, w %g, h %g]", box->X, box->Y, box->Width, box->Height); pango_cairo_update_layout (graphics->ct, layout); return layout; }
static void render_para (GdkDrawable *drawable, GtkTextRenderState *render_state, GtkTextLineDisplay *line_display, /* Top-left corner of paragraph including all margins */ int x, int y, int selection_start_index, int selection_end_index, GList **widgets) { GSList *shaped_pointer = line_display->shaped_objects; PangoLayout *layout = line_display->layout; int byte_offset = 0; PangoLayoutIter *iter; PangoRectangle layout_logical; int screen_width; GdkGC *fg_gc, *bg_gc; gint state; gboolean first = TRUE; iter = pango_layout_get_iter (layout); pango_layout_iter_get_layout_extents (iter, NULL, &layout_logical); /* Adjust for margins */ layout_logical.x += line_display->x_offset * PANGO_SCALE; layout_logical.y += line_display->top_margin * PANGO_SCALE; screen_width = line_display->total_width; if (GTK_WIDGET_HAS_FOCUS (render_state->widget)) state = GTK_STATE_SELECTED; else state = GTK_STATE_ACTIVE; fg_gc = render_state->widget->style->text_gc [state]; bg_gc = render_state->widget->style->base_gc [state]; do { PangoLayoutLine *line = pango_layout_iter_get_line (iter); int selection_y, selection_height; int first_y, last_y; PangoRectangle line_rect; int baseline; pango_layout_iter_get_line_extents (iter, NULL, &line_rect); baseline = pango_layout_iter_get_baseline (iter); pango_layout_iter_get_line_yrange (iter, &first_y, &last_y); /* Adjust for margins */ line_rect.x += line_display->x_offset * PANGO_SCALE; line_rect.y += line_display->top_margin * PANGO_SCALE; baseline += line_display->top_margin * PANGO_SCALE; /* Selection is the height of the line, plus top/bottom * margin if we're the first/last line */ selection_y = y + PANGO_PIXELS (first_y) + line_display->top_margin; selection_height = PANGO_PIXELS (last_y) - PANGO_PIXELS (first_y); if (first) { selection_y -= line_display->top_margin; selection_height += line_display->top_margin; } if (pango_layout_iter_at_last_line (iter)) selection_height += line_display->bottom_margin; first = FALSE; if (selection_start_index < byte_offset && selection_end_index > line->length + byte_offset) /* All selected */ { gdk_draw_rectangle (drawable, bg_gc, TRUE, x + line_display->left_margin, selection_y, screen_width, selection_height); render_layout_line (drawable, render_state, line, &shaped_pointer, x + PANGO_PIXELS (line_rect.x), y + PANGO_PIXELS (baseline), TRUE, widgets); } else { GSList *shaped_pointer_tmp = shaped_pointer; render_layout_line (drawable, render_state, line, &shaped_pointer, x + PANGO_PIXELS (line_rect.x), y + PANGO_PIXELS (baseline), FALSE, widgets); if (selection_start_index <= byte_offset + line->length && selection_end_index > byte_offset) /* Some selected */ { GdkRegion *clip_region = get_selected_clip (render_state, layout, line, x + line_display->x_offset, selection_y, selection_height, selection_start_index, selection_end_index); gdk_gc_set_clip_region (fg_gc, clip_region); gdk_gc_set_clip_region (bg_gc, clip_region); gdk_draw_rectangle (drawable, bg_gc, TRUE, x + PANGO_PIXELS (line_rect.x), selection_y, PANGO_PIXELS (line_rect.width), selection_height); render_layout_line (drawable, render_state, line, &shaped_pointer_tmp, x + PANGO_PIXELS (line_rect.x), y + PANGO_PIXELS (baseline), TRUE, widgets); gdk_gc_set_clip_region (fg_gc, NULL); gdk_gc_set_clip_region (bg_gc, NULL); gdk_region_destroy (clip_region); /* Paint in the ends of the line */ if (line_rect.x > line_display->left_margin * PANGO_SCALE && ((line_display->direction == GTK_TEXT_DIR_LTR && selection_start_index < byte_offset) || (line_display->direction == GTK_TEXT_DIR_RTL && selection_end_index > byte_offset + line->length))) { gdk_draw_rectangle (drawable, bg_gc, TRUE, x + line_display->left_margin, selection_y, PANGO_PIXELS (line_rect.x) - line_display->left_margin, selection_height); } if (line_rect.x + line_rect.width < (screen_width + line_display->left_margin) * PANGO_SCALE && ((line_display->direction == GTK_TEXT_DIR_LTR && selection_end_index > byte_offset + line->length) || (line_display->direction == GTK_TEXT_DIR_RTL && selection_start_index < byte_offset))) { int nonlayout_width; nonlayout_width = line_display->left_margin + screen_width - PANGO_PIXELS (line_rect.x) - PANGO_PIXELS (line_rect.width); gdk_draw_rectangle (drawable, bg_gc, TRUE, x + PANGO_PIXELS (line_rect.x) + PANGO_PIXELS (line_rect.width), selection_y, nonlayout_width, selection_height); } } } byte_offset += line->length; } while (pango_layout_iter_next_line (iter)); pango_layout_iter_free (iter); }