void CairoRenderer::RenderOperator(const Operator *pOp, const Object **pParams, int nParams) { const char *cstr; double x, y; double v[6]; int i, n; const Object *pObj; const Stream *pStream; const Dictionary *pDict; cairo_matrix_t matrix; int nWidth, nHeight; cairo_surface_t *pSurface; cstr = pOp->GetValue(); if (strchr("fFbBW", *cstr) != NULL) if (cstr[1] == '\0') cairo_set_fill_rule(m_pCairo, CAIRO_FILL_RULE_WINDING); else if (cstr[1] == '*') cairo_set_fill_rule(m_pCairo, CAIRO_FILL_RULE_EVEN_ODD); if (*cstr == 'b') //close, fill, and stroke { cairo_close_path(m_pCairo); cairo_fill(m_pCairo); Stroke(); } else if (strcmp(cstr, "B") == 0 || strcmp(cstr, "B*") == 0) //fill and stroke { cairo_fill(m_pCairo); Stroke(); } else if (strcmp(cstr, "BDC") == 0) { NOT_IMPLEMENTED; } else if (strcmp(cstr, "BI") == 0) { NOT_IMPLEMENTED; } else if (strcmp(cstr, "BMC") == 0) { NOT_IMPLEMENTED; } else if (strcmp(cstr, "BT") == 0) { cairo_save(m_pCairo); cairo_move_to(m_pCairo, 0.0, 0.0); m_cairo_face = NULL; } else if (strcmp(cstr, "BX") == 0) { NOT_IMPLEMENTED; } else if (strcmp(cstr, "c") == 0) //curve to { ConvertNumeric(pParams, nParams, v); cairo_curve_to(m_pCairo, v[0], v[1], v[2], v[3], v[4], v[5]); } else if (strcmp(cstr, "cm") == 0) //concat { ConvertNumeric(pParams, nParams, v); cairo_matrix_init(&matrix, v[0], v[1], v[2], v[3], v[4], v[5]); cairo_transform(m_pCairo, &matrix); } else if (strcmp(cstr, "CS") == 0) //color space { NOT_IMPLEMENTED; } else if (strcmp(cstr, "cs") == 0) //color space { NOT_IMPLEMENTED; } else if (strcmp(cstr, "d") == 0) //line dash SetDash(pParams[0], pParams[1]); else if (strcmp(cstr, "d0") == 0) { NOT_IMPLEMENTED; } else if (strcmp(cstr, "d1") == 0) { NOT_IMPLEMENTED; } else if (strcmp(cstr, "Do") == 0) { pStream = (const Stream *)GetResource(XOBJECT, ((Name *)pParams[0])->GetValue()); pDict = pStream->GetDictionary(); pObj = pDict->GetValue("Subtype"); if (strcmp(((const Name *)pObj)->GetValue(), "Image") == 0) { nWidth = ((const Numeric *)pDict->GetValue("Width"))->GetValue(); nHeight = ((const Numeric *)pDict->GetValue("Height"))->GetValue(); cairo_matrix_init(&matrix, 1.0 / nWidth, 0.0, 0.0, -1.0 / nHeight, 0.0, 1.0); cairo_save(m_pCairo); cairo_transform(m_pCairo, &matrix); cairo_rectangle(m_pCairo, 0.0, 0.0, nWidth, nHeight); cairo_clip(m_pCairo); pSurface = CreateImageSurface(pStream, nWidth, nHeight); cairo_set_source_surface(m_pCairo, pSurface, 0.0, 0.0); cairo_paint(m_pCairo); cairo_surface_destroy(pSurface); cairo_restore(m_pCairo); } } else if (strcmp(cstr, "DP") == 0) { NOT_IMPLEMENTED; } else if (strcmp(cstr, "EI") == 0) { NOT_IMPLEMENTED; } else if (strcmp(cstr, "EMC") == 0) { NOT_IMPLEMENTED; } else if (strcmp(cstr, "ET") == 0) { cairo_restore(m_pCairo); if (m_cairo_face) { cairo_set_font_face(m_pCairo, NULL); cairo_font_face_destroy(m_cairo_face); } } else if (strcmp(cstr, "EX") == 0) { NOT_IMPLEMENTED; } else if (*cstr == 'f' || *cstr == 'F') //fill cairo_fill(m_pCairo); else if (strcmp(cstr, "G") == 0) { ConvertNumeric(pParams, nParams, v); m_pStrokeColor[0] = v[0]; m_pStrokeColor[1] = v[0]; m_pStrokeColor[2] = v[0]; } else if (strcmp(cstr, "g") == 0) { ConvertNumeric(pParams, nParams, v); cairo_set_source_rgba(m_pCairo, v[0], v[0], v[0], 1.0); } else if (strcmp(cstr, "gs") == 0) //set graphics state SetGraphicsState(((const Name *)pParams[0])->GetValue()); else if (strcmp(cstr, "h") == 0) //close subpath cairo_close_path(m_pCairo); else if (strcmp(cstr, "i") == 0) //flatness tolerance { ConvertNumeric(pParams, nParams, v); cairo_set_tolerance(m_pCairo, v[0]); } else if (strcmp(cstr, "ID") == 0) { NOT_IMPLEMENTED; } else if (strcmp(cstr, "j") == 0) //line join { ConvertNumeric(pParams, nParams, v); cairo_set_line_join(m_pCairo, (cairo_line_join_t)v[0]); } else if (strcmp(cstr, "J") == 0) //line cap { ConvertNumeric(pParams, nParams, v); cairo_set_line_cap(m_pCairo, (cairo_line_cap_t)v[0]); } else if (strcmp(cstr, "K") == 0) { ConvertNumeric(pParams, nParams, v); m_pStrokeColor[0] = (1.0 - v[0]) * (1.0 - v[3]); m_pStrokeColor[1] = (1.0 - v[1]) * (1.0 - v[3]); m_pStrokeColor[2] = (1.0 - v[2]) * (1.0 - v[3]); } else if (strcmp(cstr, "k") == 0) { ConvertNumeric(pParams, nParams, v); cairo_set_source_rgba(m_pCairo, (1.0 - v[0]) * (1.0 - v[3]), (1.0 - v[1]) * (1.0 - v[3]), (1.0 - v[2]) * (1.0 - v[3]), 1.0); } else if (strcmp(cstr, "l") == 0) //line to { ConvertNumeric(pParams, nParams, v); cairo_line_to(m_pCairo, v[0], v[1]); } else if (strcmp(cstr, "m") == 0) //new sub path { ConvertNumeric(pParams, nParams, v); cairo_move_to(m_pCairo, v[0], v[1]); } else if (strcmp(cstr, "M") == 0) //miter limit { ConvertNumeric(pParams, nParams, v); cairo_set_miter_limit(m_pCairo, v[0]); } else if (strcmp(cstr, "MP") == 0) { NOT_IMPLEMENTED; } else if (strcmp(cstr, "n") == 0) //end path cairo_new_path(m_pCairo); else if (strcmp(cstr, "q") == 0) //save graphics state cairo_save(m_pCairo); else if (strcmp(cstr, "Q") == 0) //restore graphics state cairo_restore(m_pCairo); else if (strcmp(cstr, "re") == 0) //rectangle { ConvertNumeric(pParams, nParams, v); cairo_rectangle(m_pCairo, v[0], v[1], v[2], v[3]); } else if (strcmp(cstr, "RG") == 0) { ConvertNumeric(pParams, nParams, m_pStrokeColor); } else if (strcmp(cstr, "rg") == 0) { ConvertNumeric(pParams, nParams, v); cairo_set_source_rgba(m_pCairo, v[0], v[1], v[2], 1.0); } else if (strcmp(cstr, "ri") == 0) //color rendering intent SetIntent(((const Name *)pParams[0])->GetValue()); else if (strcmp(cstr, "s") == 0) //close and stroke { cairo_close_path(m_pCairo); Stroke(); } else if (strcmp(cstr, "S") == 0) //stroke Stroke(); else if (strcmp(cstr, "SC") == 0) { NOT_IMPLEMENTED; } else if (strcmp(cstr, "sc") == 0) { NOT_IMPLEMENTED; } else if (strcmp(cstr, "SCN") == 0) { NOT_IMPLEMENTED; } else if (strcmp(cstr, "scn") == 0) { NOT_IMPLEMENTED; } else if (strcmp(cstr, "sh") == 0) { NOT_IMPLEMENTED; } else if (strcmp(cstr, "T*") == 0) { cairo_translate(m_pCairo, 0.0, -m_dTextLead); cairo_move_to(m_pCairo, 0.0, 0.0); } else if (strcmp(cstr, "Tc") == 0) { NOT_IMPLEMENTED; } else if (strcmp(cstr, "Td") == 0) { ConvertNumeric(pParams, nParams, v); cairo_translate(m_pCairo, v[0], v[1]); cairo_move_to(m_pCairo, 0.0, 0.0); } else if (strcmp(cstr, "TD") == 0) { ConvertNumeric(pParams, nParams, v); cairo_translate(m_pCairo, v[0], v[1]); cairo_move_to(m_pCairo, 0.0, 0.0); m_dTextLead = -v[1]; } else if (strcmp(cstr, "Tf") == 0) { ChangeFont(((const Name *)pParams[0])->GetValue()); SetFontFace(m_pFontData->GetFontFile()); ConvertNumeric(pParams + 1, nParams - 1, v); cairo_matrix_init_scale(m_pFontMatrix, v[0], -v[0]); cairo_set_font_matrix(m_pCairo, m_pFontMatrix); } else if (strcmp(cstr, "Tj") == 0) RenderString((const String *)pParams[0]); else if (strcmp(cstr, "TJ") == 0) { n = ((const Array *)pParams[0])->GetSize(); for (i = 0; i < n; i++) { pObj = ((const Array *)pParams[0])->GetValue(i); if (pObj->GetType() == Object::OBJ_STRING) RenderString((const String *)pObj); else if (pObj->GetType() == Object::OBJ_NUMERIC) cairo_translate(m_pCairo, -((const Numeric *)pObj)->GetValue() / 1000.0, 0.0); } } else if (strcmp(cstr, "TL") == 0) { ConvertNumeric(pParams, nParams, v); m_dTextLead = v[0]; } else if (strcmp(cstr, "Tm") == 0) { ConvertNumeric(pParams, nParams, v); cairo_matrix_init(&matrix, v[0], v[1], v[2], v[3], v[4], v[5]); cairo_matrix_multiply(&matrix, m_pFontMatrix, &matrix); cairo_set_font_matrix(m_pCairo, &matrix); cairo_move_to(m_pCairo, 0.0, 0.0); } else if (strcmp(cstr, "Tr") == 0) { ConvertNumeric(pParams, nParams, v); m_nTextMode = v[0]; } else if (strcmp(cstr, "Ts") == 0) { NOT_IMPLEMENTED; } else if (strcmp(cstr, "Tw") == 0) { NOT_IMPLEMENTED; } else if (strcmp(cstr, "Tz") == 0) { ConvertNumeric(pParams, nParams, v); cairo_scale(m_pCairo, v[0] / 100.0, 1.0); } else if (strcmp(cstr, "v") == 0) //curve to { ConvertNumeric(pParams, nParams, v); cairo_get_current_point(m_pCairo, &x, &y); cairo_curve_to(m_pCairo, x, y, v[0], v[1], v[2], v[3]); } else if (strcmp(cstr, "w") == 0) //line width { ConvertNumeric(pParams, nParams, v); cairo_set_line_width(m_pCairo, v[0] + 0.5); } else if (*cstr == 'W') //clipping path cairo_clip(m_pCairo); else if (strcmp(cstr, "y") == 0) //curve to { ConvertNumeric(pParams, nParams, v); cairo_curve_to(m_pCairo, v[0], v[1], v[2], v[3], v[2], v[3]); } else if (strcmp(cstr, "'") == 0) { cairo_translate(m_pCairo, 0.0, -m_dTextLead); cairo_move_to(m_pCairo, 0.0, 0.0); RenderString((const String *)pParams[0]); } else if (strcmp(cstr, "\"") == 0) { cairo_translate(m_pCairo, 0.0, -m_dTextLead); cairo_move_to(m_pCairo, 0.0, 0.0); RenderString((const String *)pParams[2]); } else { assert(false); } }
LOCAL ushort MergeLists (ushort tList, ushort nList, ushort Count) { uchar *TypeIndexString, *NameOffsetString; uchar *ScratchString; // temporary work uchar *ScratchSave; uchar *OffsetStart; ushort Length; ushort FinalLength; int i; CV_fldattr_t mattrib = {0}; TENTRY *TypeEntry, *NameEntry; CV_typ_t forward; mattrib.access = CV_public; // public access field TypeEntry = GetTypeEntry ((CV_typ_t)(tList - 512), &forward); NameEntry = GetTypeEntry ((CV_typ_t)(nList - 512), &forward); // Get the two strings to walk TypeIndexString = TypeEntry->TypeString; NameOffsetString = NameEntry->TypeString; // Calculate the longest possible result // We are intentionally wasting memory to avoid walking the list // two times. Length = LNGTHSZ // Size of length field + MAXPAD // So we can align the start + offsetof (lfFieldList, data) // Field leaf size + (LENGTH (NameOffsetString) - 1) // Variable length data size + (Count // Number of fields times * (offsetof (lfMember, offset) // Size LF_MEMBER structure plus + MAXPAD // Maximum number of pad bytes per field + MAXC6NUMERICGROWTH)); // Maximum possible growth of numeric field TypeIndexString += 4; // skip to indices NameOffsetString += 4; // skip to names ScratchString = GetScratchString (Length); // get a scratch string //M00SPEED This logic could be moved to GetScratchSize // This garantees we can do padding when running with any malloc version while((ulong)ScratchString & MAXPAD) { // Make sure buffer starts on a four byte boundry ScratchString++; } ScratchSave = ScratchString; // Start building new C7 field list ScratchString += LNGTHSZ; // Skip Length (fill in later with exact size) *((ushort *)ScratchString)++ = LF_FIELDLIST; for (; Count > 0; Count --) { DASSERT(*NameOffsetString == OLF_NAME); DASSERT(*TypeIndexString == OLF_INDEX); NameOffsetString ++; // skip OLF_NAME *((ushort *)ScratchString)++ = LF_MEMBER; *((ushort *)ScratchString)++ = getindex (TypeIndexString); *((CV_fldattr_t *)ScratchString)++ = mattrib; // Temporarily skip over the string OffsetStart = NameOffsetString + *NameOffsetString + 1; ConvertNumeric (&OffsetStart, &ScratchString); // copy over the name for (i = *NameOffsetString + 1; i; i --) { *ScratchString ++ = *NameOffsetString ++; } // update the name offset string NameOffsetString = OffsetStart; // Pad the new leaf if ((ulong)ScratchString & MAXPAD) { *ScratchString = (uchar)(0xF0 + MAXPAD + 1 - ((ulong)ScratchString & MAXPAD)); while((ulong)(++ScratchString) & MAXPAD) { *ScratchString = 0; } } } TypeIndexString = TypeEntry->TypeString; NameOffsetString = NameEntry->TypeString; FinalLength = ScratchString - ScratchSave; DASSERT(FinalLength <= Length); *((ushort *)(ScratchSave)) = FinalLength - LNGTHSZ; // Allocate memory and copy the type string into it TypeIndexString = AllocNewStr (TypeEntry, FinalLength); TypeEntry->flags.IsNewFormat = TRUE; memcpy (TypeIndexString, ScratchSave, FinalLength); return (tList); }