1 /*
2 For general Scribus (>=1.3.2) copyright and licensing information please refer
3 to the COPYING file provided with the program. Following this notice may exist
4 a copyright and/or license notice that predates the release of Scribus 1.3.2
5 for which a new license (GPL+exception) is in place.
6 */
7 /***************************************************************************
8 	begin				: 2005
9 	copyright			: (C) 2005 by Franz Schmid
10 	email				: Franz.Schmid@altmuehlnet.de
11 	copyright			: (C) 2005 by Craig Bradney
12 	email				: cbradney@zip.com.au
13 ***************************************************************************/
14 
15 /***************************************************************************
16 *																		 *
17 *   Scribus program is free software; you can redistribute it and/or modify  *
18 *   it under the terms of the GNU General Public License as published by  *
19 *   the Free Software Foundation; either version 2 of the License, or	 *
20 *   (at your option) any later version.								   *
21 *																		 *
22 ***************************************************************************/
23 
24 #include "commonstrings.h"
25 #include "documentchecker.h"
26 #include "pageitem.h"
27 #include "pdf_analyzer.h"
28 #include "sccolor.h"
29 #include "sclayer.h"
30 #include "scpage.h"
31 #include "scribusdoc.h"
32 #include "scribusstructs.h"
33 #include "text/textlayoutpainter.h"
34 #include "util.h"
35 #include "util_formats.h"
36 
37 #include <QList>
38 
39 
40 class MissingGlyphsPainter: public TextLayoutPainter
41 {
42 	errorCodes& m_itemError;
43 //	const TextLayout& m_textLayout;
44 
45 public:
MissingGlyphsPainter(errorCodes & itemError,const TextLayout &)46 	MissingGlyphsPainter(errorCodes& itemError, const TextLayout&  /*textLayout*/)
47 		: m_itemError(itemError)
48 //		, m_textLayout(textLayout)
49 	{ }
50 
drawGlyph(const GlyphCluster & gc)51 	void drawGlyph(const GlyphCluster& gc) override
52 	{
53 		if (gc.isEmpty())
54 		{
55 			int pos = gc.firstChar();
56 			m_itemError.insert(MissingGlyph, pos);
57 		}
58 	}
drawGlyphOutline(const GlyphCluster & gc,bool)59 	void drawGlyphOutline(const GlyphCluster& gc, bool) override
60 	{
61 		drawGlyph(gc);
62 	}
drawLine(QPointF,QPointF)63 	void drawLine(QPointF, QPointF) override { }
drawRect(QRectF)64 	void drawRect(QRectF) override { }
drawObject(PageItem *)65 	void drawObject(PageItem*) override { }
66 };
67 
isPartFilledImageFrame(PageItem * currItem)68 bool isPartFilledImageFrame(PageItem * currItem)
69 {
70 	double imageRealWidth  = currItem->imageXScale() * currItem->pixm.imgInfo.lowResScale * currItem->pixm.width();
71 	double imageRealHeight = currItem->imageYScale() * currItem->pixm.imgInfo.lowResScale * currItem->pixm.height();
72 //	qDebug() << "X" << currItem->width() << imageRealWidth;
73 //	qDebug() << "Y" << currItem->height() << imageRealHeight;
74 	return ((currItem->width() - imageRealWidth) > 0.05 || (currItem->height() - imageRealHeight) > 0.05);
75 }
76 
77 
checkDocument(ScribusDoc * currDoc)78 bool DocumentChecker::checkDocument(ScribusDoc *currDoc)
79 {
80 	const auto& checkerProfiles = currDoc->checkerProfiles();
81 	if (!checkerProfiles.contains(currDoc->curCheckProfile()))
82 		return false;
83 	return checkDocument(currDoc, currDoc->curCheckProfile());
84 }
85 
checkDocument(ScribusDoc * currDoc,const QString & checkerProfile)86 bool DocumentChecker::checkDocument(ScribusDoc *currDoc, const QString& checkerProfile)
87 {
88 	const auto& checkerProfiles = currDoc->checkerProfiles();
89 	if (!checkerProfiles.contains(checkerProfile))
90 		return false;
91 
92 	struct CheckerPrefs checkerSettings;
93 	checkerSettings = checkerProfiles[checkerProfile];
94 	currDoc->pageErrors.clear();
95 	currDoc->docItemErrors.clear();
96 	currDoc->masterItemErrors.clear();
97 	currDoc->docLayerErrors.clear();
98 
99 	checkPages(currDoc, checkerSettings);
100 	checkLayers(currDoc, checkerSettings);
101 	//update all marks references and check if that changes anything in doc
102 	currDoc->setNotesChanged(currDoc->updateMarks(true));
103 
104 	checkItems(currDoc, checkerSettings);
105 
106 	return (currDoc->hasPreflightErrors());
107 }
108 
checkPages(ScribusDoc * currDoc,struct CheckerPrefs checkerSettings)109 void DocumentChecker::checkPages(ScribusDoc *currDoc, struct CheckerPrefs checkerSettings)
110 {
111 	errorCodes pageError;
112 	for (int i=0; i < currDoc->DocPages.count(); ++i )
113 	{
114 		pageError.clear();
115 		if (checkerSettings.checkAppliedMasterDifferentSide)
116 		{
117 			bool error = false;
118 			int masterPageNumber = -1, masterPageLocation = -1;
119 			PageLocation pageLoc = currDoc->locationOfPage(i);
120 			masterPageNumber = currDoc->MasterNames.value(currDoc->DocPages[i]->masterPageName(), -1);
121 			if (masterPageNumber >= 0)
122 				masterPageLocation = currDoc->MasterPages[masterPageNumber]->LeftPg;
123 			if (currDoc->pagePositioning() == singlePage)
124 			{
125 				if ((pageLoc != LeftPage) || (masterPageLocation != 0))
126 					error = true;
127 			}
128 			else
129 			{
130 				if (pageLoc==LeftPage && masterPageLocation==1)
131 					error = false;
132 				else if (pageLoc==RightPage && masterPageLocation==0)
133 					error = false;
134 				else if (pageLoc==MiddlePage && masterPageLocation==2)
135 					error = false;
136 				else
137 					error = true;
138 			}
139 			if (error)
140 				pageError.insert(AppliedMasterDifferentSide, 0);
141 		}
142 		if (pageError.count() != 0)
143 			currDoc->pageErrors.insert(i, pageError);
144 	}
145 }
146 
checkLayers(ScribusDoc * currDoc,struct CheckerPrefs checkerSettings)147 void DocumentChecker::checkLayers(ScribusDoc *currDoc, struct CheckerPrefs checkerSettings)
148 {
149 	errorCodes layerError;
150 	int Lnr;
151 	ScLayer ll;
152 	ll.ID = 0;
153 	Lnr = 0;
154 	uint layerCount= currDoc->layerCount();
155 	for (uint la = 0; la < layerCount; ++la)
156 	{
157 		layerError.clear();
158 		currDoc->Layers.levelToLayer(ll, Lnr);
159 		if ((ll.isViewable != ll.isPrintable) && (checkerSettings.checkOffConflictLayers))
160 			layerError.insert(OffConflictLayers, 0);
161 		if ((!ll.isViewable) && (checkerSettings.ignoreOffLayers))
162 			continue;
163 		if ((!ll.isPrintable) && (checkerSettings.ignoreOffLayers))
164 			continue;
165 		if ((ll.transparency != 1.0) && (checkerSettings.checkTransparency))
166 			layerError.insert(Transparency, 0);
167 		if ((ll.blendMode != 0) && (checkerSettings.checkTransparency))
168 			layerError.insert(BlendMode, 1);
169 		Lnr++;
170 		if (layerError.count() != 0)
171 			currDoc->docLayerErrors.insert(ll.ID, layerError);
172 	}
173 }
174 
checkItems(ScribusDoc * currDoc,struct CheckerPrefs checkerSettings)175 void DocumentChecker::checkItems(ScribusDoc *currDoc, struct CheckerPrefs checkerSettings)
176 {
177 	errorCodes itemError;
178 
179 	QList<PageItem*> allItems;
180 	uint masterItemsCount = currDoc->MasterItems.count();
181 	for (uint i = 0; i < masterItemsCount; ++i)
182 	{
183 		PageItem* currItem = currDoc->MasterItems.at(i);
184 		if (currItem->isGroup())
185 			allItems = currItem->getAllChildren();
186 		else
187 			allItems.append(currItem);
188 		for (int ii = 0; ii < allItems.count(); ii++)
189 		{
190 			currItem = allItems.at(ii);
191 			if (!currItem->printEnabled())
192 				continue;
193 			if (!(currDoc->layerPrintable(currItem->m_layerID)) && (checkerSettings.ignoreOffLayers))
194 				continue;
195 			itemError.clear();
196 			if (((currItem->isAnnotation()) || (currItem->isBookmark)) && (checkerSettings.checkAnnotations))
197 				itemError.insert(PDFAnnotField, 0);
198 			if (currItem->hasSoftShadow() && checkerSettings.checkTransparency)
199 				itemError.insert(Transparency, 0);
200 			if ((currItem->GrType == 0) && (checkerSettings.checkTransparency))
201 			{
202 				if (currItem->fillColor() != CommonStrings::None)
203 				{
204 					if ((currItem->fillTransparency() != 0.0) || (currItem->fillBlendmode() != 0))
205 						itemError.insert(Transparency, 0);
206 				}
207 			}
208 			if ((currItem->GrType != 0) && (checkerSettings.checkTransparency))
209 			{
210 				if (currItem->GrType == Gradient_4Colors)
211 				{
212 					if (currItem->GrCol1transp != 1.0)
213 						itemError.insert(Transparency, 0);
214 					else if (currItem->GrCol2transp != 1.0)
215 						itemError.insert(Transparency, 0);
216 					else if (currItem->GrCol3transp != 1.0)
217 						itemError.insert(Transparency, 0);
218 					else if (currItem->GrCol4transp != 1.0)
219 						itemError.insert(Transparency, 0);
220 				}
221 				else if (currItem->GrType == Gradient_Mesh)
222 				{
223 					for (int grow = 0; grow < currItem->meshGradientArray.count(); grow++)
224 					{
225 						for (int gcol = 0; gcol < currItem->meshGradientArray[grow].count(); gcol++)
226 						{
227 							if (currItem->meshGradientArray[grow][gcol].transparency != 1.0)
228 								itemError.insert(Transparency, 0);
229 						}
230 					}
231 				}
232 				else if (currItem->GrType == Gradient_PatchMesh)
233 				{
234 					for (int grow = 0; grow < currItem->meshGradientPatches.count(); grow++)
235 					{
236 						meshGradientPatch patch = currItem->meshGradientPatches[grow];
237 						if (currItem->meshGradientPatches[grow].TL.transparency != 1.0)
238 							itemError.insert(Transparency, 0);
239 						if (currItem->meshGradientPatches[grow].TR.transparency != 1.0)
240 							itemError.insert(Transparency, 0);
241 						if (currItem->meshGradientPatches[grow].BR.transparency != 1.0)
242 							itemError.insert(Transparency, 0);
243 						if (currItem->meshGradientPatches[grow].BL.transparency != 1.0)
244 							itemError.insert(Transparency, 0);
245 					}
246 				}
247 				else
248 				{
249 					QList<VColorStop*> colorStops = currItem->fill_gradient.colorStops();
250 					for (int offset = 0 ; offset < colorStops.count() ; offset++)
251 					{
252 						if (colorStops[offset]->opacity != 1.0)
253 						{
254 							itemError.insert(Transparency, 0);
255 							break;
256 						}
257 					}
258 				}
259 			}
260 			if ((currItem->GrTypeStroke == 0) && (checkerSettings.checkTransparency))
261 			{
262 				if ((currItem->lineColor() != CommonStrings::None) || !currItem->NamedLStyle.isEmpty())
263 				{
264 					if ((currItem->lineTransparency() != 0.0) || (currItem->lineBlendmode() != 0))
265 						itemError.insert(Transparency, 0);
266 				}
267 			}
268 			if ((currItem->GrTypeStroke != 0) && (checkerSettings.checkTransparency))
269 			{
270 				QList<VColorStop*> colorStops = currItem->stroke_gradient.colorStops();
271 				for (int offset = 0 ; offset < colorStops.count() ; offset++)
272 				{
273 					if (colorStops[offset]->opacity != 1.0)
274 					{
275 						itemError.insert(Transparency, 0);
276 						break;
277 					}
278 				}
279 			}
280 			if ((currItem->GrMask > 0) && (checkerSettings.checkTransparency))
281 				itemError.insert(Transparency, 0);
282 			if ((currItem->OwnPage == -1) && (checkerSettings.checkOrphans))
283 				itemError.insert(ObjectNotOnPage, 0);
284 			if (currItem->isImageFrame() && !currItem->isOSGFrame())
285 			{
286 
287 				// check image vs. frame sizes
288 				if (checkerSettings.checkPartFilledImageFrames && isPartFilledImageFrame(currItem))
289 				{
290 					itemError.insert(PartFilledImageFrame, 0);
291 				}
292 
293 				if ((!currItem->imageIsAvailable) && (checkerSettings.checkPictures))
294 					itemError.insert(MissingImage, 0);
295 				else
296 				{
297 					if (currItem->imageIsAvailable)
298 					{
299 						if (checkerSettings.checkTransparency && currItem->pixm.hasSmoothAlpha())
300 							itemError.insert(Transparency, 0);
301 					}
302 					if  (((qRound(72.0 / currItem->imageXScale()) < checkerSettings.minResolution) || (qRound(72.0 / currItem->imageYScale()) < checkerSettings.minResolution))
303 							&& (currItem->isRaster) && (checkerSettings.checkResolution))
304 						itemError.insert(ImageDPITooLow, 0);
305 					if  (((qRound(72.0 / currItem->imageXScale()) > checkerSettings.maxResolution) || (qRound(72.0 / currItem->imageYScale()) > checkerSettings.maxResolution))
306 							&& (currItem->isRaster) && (checkerSettings.checkResolution))
307 						itemError.insert(ImageDPITooHigh, 0);
308 					QFileInfo fi = QFileInfo(currItem->Pfile);
309 					QString ext = fi.suffix().toLower();
310 					if (extensionIndicatesPDF(ext) && (checkerSettings.checkRasterPDF))
311 						itemError.insert(PlacedPDF, 0);
312 					if ((ext == "gif") && (checkerSettings.checkForGIF))
313 						itemError.insert(ImageIsGIF, 0);
314 
315 					if (extensionIndicatesPDF(ext))
316 					{
317 						PDFAnalyzer analyst(currItem->Pfile);
318 						QList<PDFColorSpace> usedColorSpaces;
319 						bool hasTransparency = false;
320 						QList<PDFFont> usedFonts;
321 						int pageNum = qMin(qMax(1, currItem->pixm.imgInfo.actualPageNumber), currItem->pixm.imgInfo.numberOfPages) - 1;
322 						QList<PDFImage> imgs;
323 						bool succeeded = analyst.inspectPDF(pageNum, usedColorSpaces, hasTransparency, usedFonts, imgs);
324 						if (succeeded)
325 						{
326 							if (checkerSettings.checkNotCMYKOrSpot || checkerSettings.checkDeviceColorsAndOutputIntent)
327 							{
328 								eColorSpaceType currPrintProfCS = ColorSpace_Unknown;
329 								if (currDoc->HasCMS)
330 								{
331 									ScColorProfile printerProf = currDoc->DocPrinterProf;
332 									currPrintProfCS = printerProf.colorSpace();
333 								}
334 								if (checkerSettings.checkNotCMYKOrSpot)
335 								{
336 									for (int i=0; i<usedColorSpaces.size(); ++i)
337 									{
338 										if (usedColorSpaces[i] == CS_DeviceRGB || usedColorSpaces[i] == CS_ICCBased || usedColorSpaces[i] == CS_CalGray
339 											|| usedColorSpaces[i] == CS_CalRGB || usedColorSpaces[i] == CS_Lab)
340 										{
341 											itemError.insert(NotCMYKOrSpot, 0);
342 											break;
343 										}
344 									}
345 								}
346 								if (checkerSettings.checkDeviceColorsAndOutputIntent && currDoc->HasCMS)
347 								{
348 									for (int i=0; i<usedColorSpaces.size(); ++i)
349 									{
350 										if (currPrintProfCS == ColorSpace_Cmyk && (usedColorSpaces[i] == CS_DeviceRGB || usedColorSpaces[i] == CS_DeviceGray))
351 										{
352 											itemError.insert(DeviceColorsAndOutputIntent, 0);
353 											break;
354 										}
355 										if (currPrintProfCS == ColorSpace_Rgb && (usedColorSpaces[i] == CS_DeviceCMYK || usedColorSpaces[i] == CS_DeviceGray))
356 										{
357 											itemError.insert(DeviceColorsAndOutputIntent, 0);
358 											break;
359 										}
360 									}
361 								}
362 							}
363 							if (checkerSettings.checkTransparency && hasTransparency)
364 								itemError.insert(Transparency, 0);
365 							if (checkerSettings.checkFontNotEmbedded || checkerSettings.checkFontIsOpenType)
366 							{
367 								for (int i=0; i<usedFonts.size(); ++i)
368 								{
369 									PDFFont currentFont = usedFonts[i];
370 									if (!currentFont.isEmbedded && checkerSettings.checkFontNotEmbedded)
371 										itemError.insert(FontNotEmbedded, 0);
372 									if (currentFont.isEmbedded && currentFont.isOpenType && checkerSettings.checkFontIsOpenType)
373 										itemError.insert(EmbeddedFontIsOpenType, 0);
374 								}
375 							}
376 							if (checkerSettings.checkResolution)
377 							{
378 								for (int i=0; i<imgs.size(); ++i)
379 								{
380 									if ((imgs[i].dpiX < checkerSettings.minResolution) || (imgs[i].dpiY < checkerSettings.minResolution))
381 										itemError.insert(ImageDPITooLow, 0);
382 									if ((imgs[i].dpiX > checkerSettings.maxResolution) || (imgs[i].dpiY > checkerSettings.maxResolution))
383 										itemError.insert(ImageDPITooHigh, 0);
384 								}
385 							}
386 						}
387 					}
388 				}
389 			}
390 			if ((currItem->isTextFrame()) || (currItem->isPathText()))
391 			{
392 				if ( currItem->frameOverflows() && (checkerSettings.checkOverflow) && (!((currItem->isAnnotation()) && ((currItem->annotation().Type() == Annotation::Combobox) || (currItem->annotation().Type() == Annotation::Listbox)))))
393 					itemError.insert(TextOverflow, 0);
394 
395 				if (checkerSettings.checkEmptyTextFrames && (currItem->itemText.length() == 0 || currItem->frameUnderflows()))
396 				{
397 					bool isEmptyAnnotation = (currItem->isAnnotation() &&
398 					                         ((currItem->annotation().Type() == Annotation::Link) ||
399 					                          (currItem->annotation().Type() == Annotation::Checkbox) ||
400 					                          (currItem->annotation().Type() == Annotation::RadioButton)));
401 					if (!isEmptyAnnotation)
402 						itemError.insert(EmptyTextFrame, 0);
403 				}
404 
405 				if (currItem->isAnnotation())
406 				{
407 					ScFace::FontFormat fformat = currItem->itemText.defaultStyle().charStyle().font().format();
408 					if (!(fformat == ScFace::SFNT || fformat == ScFace::TTCF))
409 						itemError.insert(WrongFontInAnnotation, 0);
410 				}
411 
412 				if (checkerSettings.checkGlyphs)
413 				{
414 					if (currItem->invalid)
415 						currItem->layout();
416 					MissingGlyphsPainter p(itemError, currItem->textLayout);
417 					currItem->textLayout.render(&p);
418 				}
419 			}
420 			if (((currItem->fillColor() != CommonStrings::None) || (currItem->lineColor() != CommonStrings::None)) && (checkerSettings.checkNotCMYKOrSpot))
421 			{
422 				bool rgbUsed = false;
423 				if ((currItem->fillColor() != CommonStrings::None))
424 				{
425 					ScColor tmpC = currDoc->PageColors[currItem->fillColor()];
426 					if (tmpC.getColorModel() == colorModelRGB)
427 						rgbUsed = true;
428 				}
429 				if ((currItem->lineColor() != CommonStrings::None))
430 				{
431 					ScColor tmpC = currDoc->PageColors[currItem->lineColor()];
432 					if (tmpC.getColorModel() == colorModelRGB)
433 						rgbUsed = true;
434 				}
435 				if (rgbUsed)
436 					itemError.insert(NotCMYKOrSpot, 0);
437 			}
438 			if (itemError.count() != 0)
439 				currDoc->masterItemErrors.insert(currItem, itemError);
440 		}
441 		allItems.clear();
442 	}
443 	allItems.clear();
444 	uint docItemsCount = currDoc->DocItems.count();
445 	for (uint i = 0; i < docItemsCount; ++i)
446 	{
447 		PageItem* currItem = currDoc->DocItems.at(i);
448 		if (currItem->isGroup())
449 			allItems = currItem->getAllChildren();
450 		else
451 			allItems.append(currItem);
452 		for (int ii = 0; ii < allItems.count(); ii++)
453 		{
454 			currItem = allItems.at(ii);
455 			if (!currItem->printEnabled())
456 				continue;
457 			if (!(currDoc->layerPrintable(currItem->m_layerID)) && (checkerSettings.ignoreOffLayers))
458 				continue;
459 			itemError.clear();
460 			if (currItem->hasSoftShadow() && checkerSettings.checkTransparency)
461 				itemError.insert(Transparency, 0);
462 			if ((currItem->GrType == 0) && (checkerSettings.checkTransparency))
463 			{
464 				if (currItem->fillColor() != CommonStrings::None)
465 				{
466 					if ((currItem->fillTransparency() != 0.0) || (currItem->fillBlendmode() != 0))
467 						itemError.insert(Transparency, 0);
468 				}
469 			}
470 			if ((currItem->GrType != 0) && (checkerSettings.checkTransparency))
471 			{
472 				if (currItem->GrType == Gradient_4Colors)
473 				{
474 					if (currItem->GrCol1transp != 1.0)
475 						itemError.insert(Transparency, 0);
476 					else if (currItem->GrCol2transp != 1.0)
477 						itemError.insert(Transparency, 0);
478 					else if (currItem->GrCol3transp != 1.0)
479 						itemError.insert(Transparency, 0);
480 					else if (currItem->GrCol4transp != 1.0)
481 						itemError.insert(Transparency, 0);
482 				}
483 				else if (currItem->GrType == Gradient_Mesh)
484 				{
485 					for (int grow = 0; grow < currItem->meshGradientArray.count(); grow++)
486 					{
487 						for (int gcol = 0; gcol < currItem->meshGradientArray[grow].count(); gcol++)
488 						{
489 							if (currItem->meshGradientArray[grow][gcol].transparency != 1.0)
490 								itemError.insert(Transparency, 0);
491 						}
492 					}
493 				}
494 				else if (currItem->GrType == Gradient_PatchMesh)
495 				{
496 					for (int grow = 0; grow < currItem->meshGradientPatches.count(); grow++)
497 					{
498 						meshGradientPatch patch = currItem->meshGradientPatches[grow];
499 						if (currItem->meshGradientPatches[grow].TL.transparency != 1.0)
500 							itemError.insert(Transparency, 0);
501 						if (currItem->meshGradientPatches[grow].TR.transparency != 1.0)
502 							itemError.insert(Transparency, 0);
503 						if (currItem->meshGradientPatches[grow].BR.transparency != 1.0)
504 							itemError.insert(Transparency, 0);
505 						if (currItem->meshGradientPatches[grow].BL.transparency != 1.0)
506 							itemError.insert(Transparency, 0);
507 					}
508 				}
509 				else
510 				{
511 					QList<VColorStop*> colorStops = currItem->fill_gradient.colorStops();
512 					for (int offset = 0 ; offset < colorStops.count() ; offset++)
513 					{
514 						if (colorStops[offset]->opacity != 1.0)
515 						{
516 							itemError.insert(Transparency, 0);
517 							break;
518 						}
519 					}
520 				}
521 			}
522 			if ((currItem->GrTypeStroke == 0) && (checkerSettings.checkTransparency))
523 			{
524 				if ((currItem->lineColor() != CommonStrings::None) || !currItem->NamedLStyle.isEmpty())
525 				{
526 					if ((currItem->lineTransparency() != 0.0) || (currItem->lineBlendmode() != 0))
527 						itemError.insert(Transparency, 0);
528 				}
529 			}
530 			if ((currItem->GrTypeStroke != 0) && (checkerSettings.checkTransparency))
531 			{
532 				QList<VColorStop*> colorStops = currItem->stroke_gradient.colorStops();
533 				for (int offset = 0 ; offset < colorStops.count() ; offset++)
534 				{
535 					if (colorStops[offset]->opacity != 1.0)
536 					{
537 						itemError.insert(Transparency, 0);
538 						break;
539 					}
540 				}
541 			}
542 			if ((currItem->GrMask > 0) && (checkerSettings.checkTransparency))
543 				itemError.insert(Transparency, 0);
544 			if (((currItem->isAnnotation()) || (currItem->isBookmark)) && (checkerSettings.checkAnnotations))
545 				itemError.insert(PDFAnnotField, 0);
546 			if ((currItem->OwnPage == -1) && (checkerSettings.checkOrphans))
547 				itemError.insert(ObjectNotOnPage, 0);
548 			if (currItem->isImageFrame() && !currItem->isOSGFrame())
549 			{
550 
551 				// check image vs. frame sizes
552 				if (checkerSettings.checkPartFilledImageFrames && isPartFilledImageFrame(currItem))
553 				{
554 					itemError.insert(PartFilledImageFrame, 0);
555 				}
556 
557 				if ((!currItem->imageIsAvailable) && (checkerSettings.checkPictures))
558 					itemError.insert(MissingImage, 0);
559 				else
560 				{
561 					if (currItem->imageIsAvailable)
562 					{
563 						if (checkerSettings.checkTransparency && currItem->pixm.hasSmoothAlpha())
564 							itemError.insert(Transparency, 0);
565 					}
566 					if  (((qRound(72.0 / currItem->imageXScale()) < checkerSettings.minResolution) || (qRound(72.0 / currItem->imageYScale()) < checkerSettings.minResolution))
567 							&& (currItem->isRaster) && (checkerSettings.checkResolution))
568 						itemError.insert(ImageDPITooLow, 0);
569 					if  (((qRound(72.0 / currItem->imageXScale()) > checkerSettings.maxResolution) || (qRound(72.0 / currItem->imageYScale()) > checkerSettings.maxResolution))
570 							&& (currItem->isRaster) && (checkerSettings.checkResolution))
571 						itemError.insert(ImageDPITooHigh, 0);
572 					QFileInfo fi = QFileInfo(currItem->Pfile);
573 					QString ext = fi.suffix().toLower();
574 					if (extensionIndicatesPDF(ext) && (checkerSettings.checkRasterPDF))
575 						itemError.insert(PlacedPDF, 0);
576 					if ((ext == "gif") && (checkerSettings.checkForGIF))
577 						itemError.insert(ImageIsGIF, 0);
578 
579 					if (extensionIndicatesPDF(ext))
580 					{
581 						PDFAnalyzer analyst(currItem->Pfile);
582 						QList<PDFColorSpace> usedColorSpaces;
583 						bool hasTransparency = false;
584 						QList<PDFFont> usedFonts;
585 						int pageNum = qMin(qMax(1, currItem->pixm.imgInfo.actualPageNumber), currItem->pixm.imgInfo.numberOfPages) - 1;
586 						QList<PDFImage> imgs;
587 						bool succeeded = analyst.inspectPDF(pageNum, usedColorSpaces, hasTransparency, usedFonts, imgs);
588 						if (succeeded)
589 						{
590 							if (checkerSettings.checkNotCMYKOrSpot || checkerSettings.checkDeviceColorsAndOutputIntent)
591 							{
592 								int currPrintProfCS = -1;
593 								if (currDoc->HasCMS)
594 								{
595 									ScColorProfile printerProf = currDoc->DocPrinterProf;
596 									currPrintProfCS = static_cast<int>(printerProf.colorSpace());
597 								}
598 								if (checkerSettings.checkNotCMYKOrSpot)
599 								{
600 									for (int i=0; i<usedColorSpaces.size(); ++i)
601 									{
602 										if (usedColorSpaces[i] == CS_DeviceRGB || usedColorSpaces[i] == CS_ICCBased || usedColorSpaces[i] == CS_CalGray
603 											|| usedColorSpaces[i] == CS_CalRGB || usedColorSpaces[i] == CS_Lab)
604 										{
605 											itemError.insert(NotCMYKOrSpot, 0);
606 											break;
607 										}
608 									}
609 								}
610 								if (checkerSettings.checkDeviceColorsAndOutputIntent && currDoc->HasCMS)
611 								{
612 									for (int i=0; i<usedColorSpaces.size(); ++i)
613 									{
614 										if (currPrintProfCS == ColorSpace_Cmyk && (usedColorSpaces[i] == CS_DeviceRGB || usedColorSpaces[i] == CS_DeviceGray))
615 										{
616 											itemError.insert(DeviceColorsAndOutputIntent, 0);
617 											break;
618 										}
619 										if (currPrintProfCS == ColorSpace_Rgb && (usedColorSpaces[i] == CS_DeviceCMYK || usedColorSpaces[i] == CS_DeviceGray))
620 										{
621 											itemError.insert(DeviceColorsAndOutputIntent, 0);
622 											break;
623 										}
624 									}
625 								}
626 							}
627 							if (checkerSettings.checkTransparency && hasTransparency)
628 								itemError.insert(Transparency, 0);
629 							if (checkerSettings.checkFontNotEmbedded || checkerSettings.checkFontIsOpenType)
630 							{
631 								for (int i=0; i<usedFonts.size(); ++i)
632 								{
633 									PDFFont currentFont = usedFonts[i];
634 									if (!currentFont.isEmbedded && checkerSettings.checkFontNotEmbedded)
635 										itemError.insert(FontNotEmbedded, 0);
636 									if (currentFont.isEmbedded && currentFont.isOpenType && checkerSettings.checkFontIsOpenType)
637 										itemError.insert(EmbeddedFontIsOpenType, 0);
638 								}
639 							}
640 							if (checkerSettings.checkResolution)
641 							{
642 								for (int i=0; i<imgs.size(); ++i)
643 								{
644 									if ((imgs[i].dpiX < checkerSettings.minResolution) || (imgs[i].dpiY < checkerSettings.minResolution))
645 										itemError.insert(ImageDPITooLow, 0);
646 									if ((imgs[i].dpiX > checkerSettings.maxResolution) || (imgs[i].dpiY > checkerSettings.maxResolution))
647 										itemError.insert(ImageDPITooHigh, 0);
648 								}
649 							}
650 						}
651 					}
652 				}
653 			}
654 			if ((currItem->isTextFrame()) || (currItem->isPathText()))
655 			{
656 				if ( currItem->frameOverflows() && (checkerSettings.checkOverflow) && (!((currItem->isAnnotation()) && ((currItem->annotation().Type() == Annotation::Combobox) || (currItem->annotation().Type() == Annotation::Listbox)))))
657 					itemError.insert(TextOverflow, 0);
658 
659 				if (checkerSettings.checkEmptyTextFrames && (currItem->itemText.length()==0 || currItem->frameUnderflows()))
660 				{
661 					bool isEmptyAnnotation = (currItem->isAnnotation() &&
662 					                         ((currItem->annotation().Type() == Annotation::Link) ||
663 					                          (currItem->annotation().Type() == Annotation::Checkbox) ||
664 					                          (currItem->annotation().Type() == Annotation::RadioButton)));
665 					if (!isEmptyAnnotation)
666 						itemError.insert(EmptyTextFrame, 0);
667 				}
668 
669 				if (currItem->isAnnotation())
670 				{
671 					ScFace::FontFormat fformat = currItem->itemText.defaultStyle().charStyle().font().format();
672 					if (!(fformat == ScFace::SFNT || fformat == ScFace::TTCF))
673 						itemError.insert(WrongFontInAnnotation, 0);
674 				}
675 				if (checkerSettings.checkGlyphs)
676 				{
677 					if (currItem->invalid)
678 						currItem->layout();
679 					MissingGlyphsPainter p(itemError, currItem->textLayout);
680 					currItem->textLayout.render(&p);
681 				}
682 			}
683 			if (((currItem->fillColor() != CommonStrings::None) || (currItem->lineColor() != CommonStrings::None)) && (checkerSettings.checkNotCMYKOrSpot))
684 			{
685 				bool rgbUsed = false;
686 				if ((currItem->fillColor() != CommonStrings::None))
687 				{
688 					ScColor tmpC = currDoc->PageColors[currItem->fillColor()];
689 					if (tmpC.getColorModel() == colorModelRGB)
690 						rgbUsed = true;
691 				}
692 				if ((currItem->lineColor() != CommonStrings::None))
693 				{
694 					ScColor tmpC = currDoc->PageColors[currItem->lineColor()];
695 					if (tmpC.getColorModel() == colorModelRGB)
696 						rgbUsed = true;
697 				}
698 				if (rgbUsed)
699 					itemError.insert(NotCMYKOrSpot, 0);
700 			}
701 			if (itemError.count() != 0)
702 				currDoc->docItemErrors.insert(currItem, itemError);
703 		}
704 		allItems.clear();
705 	}
706 }
707