1/*
2 * Copyright 2013, Stephan A��mus <superstippi@gmx.de>.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
5
6#include "CharacterStyle.h"
7
8
9CharacterStyle::CharacterStyle()
10	:
11	fStyleData(new CharacterStyleData(), true)
12{
13}
14
15
16CharacterStyle::CharacterStyle(const CharacterStyle& other)
17	:
18	fStyleData(other.fStyleData)
19{
20}
21
22
23CharacterStyle&
24CharacterStyle::operator=(const CharacterStyle& other)
25{
26	if (this == &other)
27		return *this;
28
29	fStyleData = other.fStyleData;
30	return *this;
31}
32
33
34bool
35CharacterStyle::operator==(const CharacterStyle& other) const
36{
37	if (this == &other)
38		return true;
39
40	if (fStyleData == other.fStyleData)
41		return true;
42
43	if (fStyleData.IsSet() && other.fStyleData.IsSet())
44		return *fStyleData == *other.fStyleData;
45
46	return false;
47}
48
49
50bool
51CharacterStyle::operator!=(const CharacterStyle& other) const
52{
53	return !(*this == other);
54}
55
56
57bool
58CharacterStyle::SetFont(const BFont& font)
59{
60	CharacterStyleDataRef data = fStyleData->SetFont(font);
61	if (data == fStyleData)
62		return data->Font() == font;
63
64	fStyleData = data;
65	return true;
66}
67
68
69const BFont&
70CharacterStyle::Font() const
71{
72	return fStyleData->Font();
73}
74
75
76bool
77CharacterStyle::SetFontSize(float size)
78{
79	BFont font(Font());
80	font.SetSize(size);
81	return SetFont(font);
82}
83
84
85float
86CharacterStyle::FontSize() const
87{
88	return Font().Size();
89}
90
91
92bool
93CharacterStyle::SetBold(bool bold)
94{
95	uint16 face = Font().Face();
96	if ((bold && (face & B_BOLD_FACE) != 0)
97		|| (!bold && (face & B_BOLD_FACE) == 0)) {
98		return true;
99	}
100
101	uint16 neededFace = face;
102	if (bold) {
103		neededFace |= B_BOLD_FACE;
104		neededFace &= ~B_REGULAR_FACE;
105	} else {
106		neededFace &= ~B_BOLD_FACE;
107		if (neededFace == 0)
108			neededFace |= B_REGULAR_FACE;
109	}
110
111	return SetFont(_FindFontForFace(neededFace));
112}
113
114
115bool
116CharacterStyle::IsBold() const
117{
118	return (Font().Face() & B_BOLD_FACE) != 0;
119}
120
121
122bool
123CharacterStyle::SetItalic(bool italic)
124{
125	uint16 face = Font().Face();
126	if ((italic && (face & B_ITALIC_FACE) != 0)
127		|| (!italic && (face & B_ITALIC_FACE) == 0)) {
128		return true;
129	}
130
131	uint16 neededFace = face;
132	if (italic) {
133		neededFace |= B_ITALIC_FACE;
134		neededFace &= ~B_REGULAR_FACE;
135	} else {
136		neededFace &= ~B_ITALIC_FACE;
137		if (neededFace == 0)
138			neededFace |= B_REGULAR_FACE;
139	}
140
141	return SetFont(_FindFontForFace(neededFace));
142}
143
144
145bool
146CharacterStyle::IsItalic() const
147{
148	return (Font().Face() & B_ITALIC_FACE) != 0;
149}
150
151
152bool
153CharacterStyle::SetAscent(float ascent)
154{
155	CharacterStyleDataRef data = fStyleData->SetAscent(ascent);
156	if (data == fStyleData)
157		return data->Ascent() == ascent;
158
159	fStyleData = data;
160	return true;
161}
162
163
164float
165CharacterStyle::Ascent() const
166{
167	return fStyleData->Ascent();
168}
169
170
171bool
172CharacterStyle::SetDescent(float descent)
173{
174	CharacterStyleDataRef data = fStyleData->SetDescent(descent);
175	if (data == fStyleData)
176		return data->Descent() == descent;
177
178	fStyleData = data;
179	return true;
180}
181
182
183float
184CharacterStyle::Descent() const
185{
186	return fStyleData->Descent();
187}
188
189
190bool
191CharacterStyle::SetWidth(float width)
192{
193	CharacterStyleDataRef data = fStyleData->SetWidth(width);
194	if (data == fStyleData)
195		return data->Width() == width;
196
197	fStyleData = data;
198	return true;
199}
200
201
202float
203CharacterStyle::Width() const
204{
205	return fStyleData->Width();
206}
207
208
209bool
210CharacterStyle::SetGlyphSpacing(float spacing)
211{
212	CharacterStyleDataRef data = fStyleData->SetGlyphSpacing(spacing);
213	if (data == fStyleData)
214		return data->GlyphSpacing() == spacing;
215
216	fStyleData = data;
217	return true;
218}
219
220
221float
222CharacterStyle::GlyphSpacing() const
223{
224	return fStyleData->GlyphSpacing();
225}
226
227
228bool
229CharacterStyle::SetForegroundColor(uint8 r, uint8 g, uint8 b, uint8 a)
230{
231	return SetForegroundColor((rgb_color){ r, g, b, a });
232}
233
234
235bool
236CharacterStyle::SetForegroundColor(color_which which)
237{
238	CharacterStyleDataRef data = fStyleData->SetForegroundColor(which);
239	if (data == fStyleData)
240		return data->WhichForegroundColor() == which;
241
242	fStyleData = data;
243	return true;
244}
245
246
247bool
248CharacterStyle::SetForegroundColor(rgb_color color)
249{
250	CharacterStyleDataRef data = fStyleData->SetForegroundColor(color);
251	if (data == fStyleData)
252		return data->ForegroundColor() == color;
253
254	fStyleData = data;
255	return true;
256}
257
258
259rgb_color
260CharacterStyle::ForegroundColor() const
261{
262	return fStyleData->ForegroundColor();
263}
264
265
266color_which
267CharacterStyle::WhichForegroundColor() const
268{
269	return fStyleData->WhichForegroundColor();
270}
271
272
273bool
274CharacterStyle::SetBackgroundColor(uint8 r, uint8 g, uint8 b, uint8 a)
275{
276	return SetBackgroundColor((rgb_color){ r, g, b, a });
277}
278
279
280bool
281CharacterStyle::SetBackgroundColor(color_which which)
282{
283	CharacterStyleDataRef data = fStyleData->SetBackgroundColor(which);
284	if (data == fStyleData)
285		return data->WhichBackgroundColor() == which;
286
287	fStyleData = data;
288	return true;
289}
290
291
292bool
293CharacterStyle::SetBackgroundColor(rgb_color color)
294{
295	CharacterStyleDataRef data = fStyleData->SetBackgroundColor(color);
296	if (data == fStyleData)
297		return data->BackgroundColor() == color;
298
299	fStyleData = data;
300	return true;
301}
302
303
304rgb_color
305CharacterStyle::BackgroundColor() const
306{
307	return fStyleData->BackgroundColor();
308}
309
310
311color_which
312CharacterStyle::WhichBackgroundColor() const
313{
314	return fStyleData->WhichBackgroundColor();
315}
316
317
318bool
319CharacterStyle::SetStrikeOutColor(color_which which)
320{
321	CharacterStyleDataRef data = fStyleData->SetStrikeOutColor(which);
322	if (data == fStyleData)
323		return data->WhichStrikeOutColor() == which;
324
325	fStyleData = data;
326	return true;
327}
328
329
330bool
331CharacterStyle::SetStrikeOutColor(rgb_color color)
332{
333	CharacterStyleDataRef data = fStyleData->SetStrikeOutColor(color);
334	if (data == fStyleData)
335		return data->StrikeOutColor() == color;
336
337	fStyleData = data;
338	return true;
339}
340
341
342rgb_color
343CharacterStyle::StrikeOutColor() const
344{
345	return fStyleData->StrikeOutColor();
346}
347
348
349color_which
350CharacterStyle::WhichStrikeOutColor() const
351{
352	return fStyleData->WhichStrikeOutColor();
353}
354
355
356bool
357CharacterStyle::SetUnderlineColor(color_which which)
358{
359	CharacterStyleDataRef data = fStyleData->SetUnderlineColor(which);
360	if (data == fStyleData)
361		return data->WhichUnderlineColor() == which;
362
363	fStyleData = data;
364	return true;
365}
366
367
368bool
369CharacterStyle::SetUnderlineColor(rgb_color color)
370{
371	CharacterStyleDataRef data = fStyleData->SetUnderlineColor(color);
372	if (data == fStyleData)
373		return data->UnderlineColor() == color;
374
375	fStyleData = data;
376	return true;
377}
378
379
380rgb_color
381CharacterStyle::UnderlineColor() const
382{
383	return fStyleData->UnderlineColor();
384}
385
386
387color_which
388CharacterStyle::WhichUnderlineColor() const
389{
390	return fStyleData->WhichUnderlineColor();
391}
392
393
394bool
395CharacterStyle::SetStrikeOut(uint8 strikeOut)
396{
397	CharacterStyleDataRef data = fStyleData->SetStrikeOut(strikeOut);
398	if (data == fStyleData)
399		return data->StrikeOut() == strikeOut;
400
401	fStyleData = data;
402	return true;
403}
404
405
406uint8
407CharacterStyle::StrikeOut() const
408{
409	return fStyleData->StrikeOut();
410}
411
412
413bool
414CharacterStyle::SetUnderline(uint8 underline)
415{
416#if 1
417	uint16 face = Font().Face();
418	if ((underline && (face & B_UNDERSCORE_FACE) != 0)
419		|| (!underline && (face & B_UNDERSCORE_FACE) == 0)) {
420		return true;
421	}
422
423	uint16 neededFace = face;
424	if (underline) {
425		neededFace |= B_UNDERSCORE_FACE;
426		neededFace &= ~B_REGULAR_FACE;
427	} else {
428		neededFace &= ~B_UNDERSCORE_FACE;
429		if (neededFace == 0)
430			neededFace |= B_REGULAR_FACE;
431	}
432
433	return SetFont(_FindFontForFace(neededFace));
434#else
435	// TODO: re-enable this instead of using B_UNDERSCORE_FACE when TextDocumentView actually
436	// implements drawing the fancy underline styles. Until then, we can at least get simple
437	// underlines.
438	CharacterStyleDataRef data = fStyleData->SetUnderline(underline);
439	if (data == fStyleData)
440		return data->Underline() == underline;
441
442	fStyleData = data;
443	return true;
444#endif
445}
446
447
448uint8
449CharacterStyle::Underline() const
450{
451	return fStyleData->Underline();
452}
453
454
455// #pragma mark - private
456
457
458BFont
459CharacterStyle::_FindFontForFace(uint16 face) const
460{
461	BFont font(Font());
462	font.SetFamilyAndFace(NULL, face);
463
464	return font;
465}
466
467