public void ReadGGC(int indexGlyph, out Composite comp, DIAction dia) { this.m_validator.DIA = dia; comp = null; GConsts.TypeGlyph typeGlyph; this.ReadTypeGlyph(indexGlyph, out typeGlyph, dia); if (typeGlyph != GConsts.TypeGlyph.Composite) { return; } int offsStart, length; if (!this.m_tableLoca.GetValidateEntryGlyf(indexGlyph, out offsStart, out length, this.m_validator, this.m_font)) { return; } MBOBuffer buffer = this.m_tableGlyf.Buffer; uint offsCur = (uint)(offsStart + Table_glyf.FieldOffsets.nextAfterHeader); bool isLast = false; try { Component component; while (!isLast) { ushort flags = buffer.GetUshort(offsCur); isLast = ((flags & (ushort)Table_glyf.MaskFlagComponent.MORE_COMPONENTS) == 0); offsCur += 2; ushort indGlyphCur = buffer.GetUshort(offsCur); // TODO: save component = new Component(indGlyphCur); // TODO: validate indGlyph is in right boundaries // TODO: add Relations to FManager offsCur += 2; bool weHaveAScale = ((flags & (ushort)Table_glyf.MaskFlagComponent.WE_HAVE_A_SCALE) != 0); bool weHaveAnXAndYScale = ((flags & (ushort)Table_glyf.MaskFlagComponent.WE_HAVE_AN_X_AND_Y_SCALE) != 0); bool weHaveATwoByTwo = ((flags & (ushort)Table_glyf.MaskFlagComponent.WE_HAVE_A_TWO_BY_TWO) != 0); int cnt = 0; if (weHaveAScale) { cnt++; } if (weHaveAnXAndYScale) { cnt++; } if (weHaveATwoByTwo) { cnt++; } if (cnt > 1) { this.m_validator.Error(T.T_NULL, E.glyf_E_CompositeAmbigousTransform, (OTTag)"glyf", "Index Component: " + indGlyphCur); return; } if ((flags & (ushort)Table_glyf.MaskFlagComponent.RESERVED) != 0) { this.m_validator.Warning(T.T_NULL, W.glyf_W_CompositeReservedBit, (OTTag)"glyf", "Index Component: " + indGlyphCur); } int arg1, arg2; if ((flags & (ushort)Table_glyf.MaskFlagComponent.ARG_1_AND_2_ARE_WORDS) != 0) { arg1 = (int)buffer.GetShort(offsCur); offsCur += 2; arg2 = (int)buffer.GetShort(offsCur); offsCur += 2; } else { arg1 = (int)buffer.GetSbyte(offsCur); offsCur += 1; arg2 = (int)buffer.GetSbyte(offsCur); offsCur += 1; } // TODO: validate bounding boxes // TODO: check that NOT BOTH shift & knots are initialized, but ONE of them IS initialized // TODO: validate that indKnots (both!) are in the right boundaries // TODO: validate that a single-point contour in any glyph is used as attachment point in at least one other glyph if ((flags & (ushort)Table_glyf.MaskFlagComponent.ARGS_ARE_XY_VALUES) != 0) { component.Shift = new VecD(arg1, arg2); } else { component.IndexKnotAttGlyph = arg1; component.IndexKnotAttComponent = arg2; } // TODO: check that matrix is non-degenerated (if not null) if (weHaveAScale) { OTF2Dot14[,] m = new OTF2Dot14[2, 2]; m[0, 0] = buffer.GetF2Dot14(offsCur); /* * // for debug only - begin * if (indGlyphCur==272) * { * m[0,0]=new OTF2Dot14(30390); * } * // for debug only - end */ offsCur += 2; m[1, 1] = m[0, 0]; component.TrOTF2Dot14 = m; } else if (weHaveAnXAndYScale) { OTF2Dot14[,] m = new OTF2Dot14[2, 2]; m[0, 0] = buffer.GetF2Dot14(offsCur); offsCur += 2; m[1, 1] = buffer.GetF2Dot14(offsCur); offsCur += 2; component.TrOTF2Dot14 = m; } else if (weHaveATwoByTwo) { OTF2Dot14[,] m = new OTF2Dot14[2, 2]; m[0, 0] = buffer.GetF2Dot14(offsCur); offsCur += 2; m[0, 1] = buffer.GetF2Dot14(offsCur); offsCur += 2; m[1, 0] = buffer.GetF2Dot14(offsCur); offsCur += 2; m[1, 1] = buffer.GetF2Dot14(offsCur); offsCur += 2; component.TrOTF2Dot14 = m; } if ((flags & (ushort)Table_glyf.MaskFlagComponent.WE_HAVE_INSTRUCTIONS) != 0) { ushort numInstr = buffer.GetUshort(offsCur); offsCur += 2; if (offsCur + numInstr > buffer.GetLength()) { throw new System.IndexOutOfRangeException(); } } if (comp == null) { comp = new Composite(); } comp.AddComponent(component); } } catch (System.IndexOutOfRangeException) { this.m_validator.Error( E._GEN_E_OffsetExceedsTableLength, (OTTag)"glyf"); if (comp != null) { comp.ClearDestroy(); comp = null; } } }
public void ReadGGO(int indexGlyph, out Outline outl, DIAction dia) { this.m_validator.DIA = dia; outl = null; GConsts.TypeGlyph typeGlyph; this.ReadTypeGlyph(indexGlyph, out typeGlyph, dia); if (typeGlyph != GConsts.TypeGlyph.Simple) { return; } int offsStart, length; if (!this.m_tableLoca.GetValidateEntryGlyf(indexGlyph, out offsStart, out length, this.m_validator, this.m_font)) { return; } MBOBuffer buffer = this.m_tableGlyf.Buffer; int iKnot; ushort[] arrIndKnotEnd; short[] arrXRel, arrYRel; byte[] arrFlag; int numCont; try { numCont = buffer.GetShort((uint)(offsStart + (int)Table_glyf.FieldOffsets.numCont)); arrIndKnotEnd = new ushort [numCont]; for (short iCont = 0; iCont < numCont; iCont++) { arrIndKnotEnd[iCont] = buffer.GetUshort((uint)(offsStart + Table_glyf.FieldOffsets.nextAfterHeader + iCont * 2)); } int numKnot = arrIndKnotEnd[numCont - 1] + 1; uint offsInstrLength = (uint)(offsStart + Table_glyf.FieldOffsets.nextAfterHeader + 2 * numCont); ushort lengthInstr = buffer.GetUshort(offsInstrLength); uint offsInstr = offsInstrLength + 2; uint offsFlag = offsInstr + lengthInstr; arrFlag = new byte [numKnot]; iKnot = 0; // index of flag in array flags uint offsCur = offsFlag; // counter of flag in the file while (iKnot < numKnot) { byte flag = buffer.GetByte(offsCur++); arrFlag[iKnot++] = flag; bool toRepeat = ((flag & (byte)(Table_glyf.MaskFlagKnot.toRepeat)) != 0); if (toRepeat) { byte numRepeat = buffer.GetByte(offsCur++); for (byte iRepeat = 0; iRepeat < numRepeat; iRepeat++) { arrFlag[iKnot++] = flag; } } } arrXRel = new short [numKnot]; arrYRel = new short [numKnot]; // read data for x-coordinates for (iKnot = 0; iKnot < numKnot; iKnot++) { if ((arrFlag[iKnot] & (byte)(Table_glyf.MaskFlagKnot.isXByte)) != 0) { byte xRel = buffer.GetByte(offsCur++); if ((arrFlag[iKnot] & (byte)(Table_glyf.MaskFlagKnot.isXSameOrPozitive)) != 0) { arrXRel[iKnot] = xRel; } else { arrXRel[iKnot] = (short)(-xRel); } } else { if ((arrFlag[iKnot] & (byte)(Table_glyf.MaskFlagKnot.isXSameOrPozitive)) != 0) { arrXRel[iKnot] = 0; } else { arrXRel[iKnot] = buffer.GetShort(offsCur); offsCur += 2; } } } // read data for y-coordinates for (iKnot = 0; iKnot < numKnot; iKnot++) { if ((arrFlag[iKnot] & (byte)(Table_glyf.MaskFlagKnot.isYByte)) != 0) { byte yRel = buffer.GetByte(offsCur++); if ((arrFlag[iKnot] & (byte)(Table_glyf.MaskFlagKnot.isYSameOrPozitive)) != 0) { arrYRel[iKnot] = yRel; } else { arrYRel[iKnot] = (short)(-yRel); } } else { if ((arrFlag[iKnot] & (byte)(Table_glyf.MaskFlagKnot.isYSameOrPozitive)) != 0) { arrYRel[iKnot] = 0; } else { arrYRel[iKnot] = buffer.GetShort(offsCur); offsCur += 2; } } } if (offsCur - 2 >= offsStart + length) { throw new System.IndexOutOfRangeException(); } } catch (System.IndexOutOfRangeException) { this.m_validator.Error( E._GEN_E_OffsetExceedsTableLength, (OTTag)"glyf"); return; } try { short xAbs = 0; short yAbs = 0; int indKnotStart, indKnotEnd = -1; outl = new Outline(); for (ushort iCont = 0; iCont < numCont; iCont++) { indKnotStart = indKnotEnd + 1; indKnotEnd = arrIndKnotEnd[iCont]; Contour cont = null; cont = new Contour(); for (iKnot = indKnotStart; iKnot <= indKnotEnd; iKnot++) { xAbs += arrXRel[iKnot]; yAbs += arrYRel[iKnot]; bool isOn = ((arrFlag[iKnot] & ((byte)(Table_glyf.MaskFlagKnot.isOnCurve))) != 0); Knot knot = new Knot(iKnot, xAbs, yAbs, isOn); cont.KnotAdd(knot); } outl.ContourAdd(cont); } } catch { outl.ClearDestroy(); outl = null; } }